Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegate Covariance Confusion Conundrum!

Why does this not work? Do I not understand delegate covariance correctly?

public delegate void MyDelegate(object obj)

public class MyClass
{
    public MyClass()
    {
         //Error: Expected method with 'void MyDelegate(object)' signature
         _delegate = MyMethod;
    }

    private MyDelegate _delegate;

    public void MyMethod(SomeObject obj)
    {}

}
like image 804
Adam Driscoll Avatar asked Feb 26 '10 21:02

Adam Driscoll


2 Answers

Correct - you don't understand covariance correctly - yet :) Your code would work if you had the same types but as return values, like this:

public delegate object MyDelegate()

public class MyClass
{
    public MyClass()
    {
         _delegate = MyMethod;
    }

    private MyDelegate _delegate;

    public SomeObject MyMethod() { return null; }
}

That would demonstrate covariance. Alternatively, you can keep it as parameters but switch the types around:

public delegate void MyDelegate(SomeObject obj)

public class MyClass
{
    public MyClass()
    {
         _delegate = MyMethod;
    }

    private MyDelegate _delegate;

    public void MyMethod(object obj) {}
}

This now demonstrates contravariance.

My rule of thumb is to ask myself, "given the delegate, what could I do with it? If I can pass in an argument which would break the method, the conversion should have failed. If the method can return something which would break the caller, the conversion should have failed."

In your code, you could have called:

_delegate(new object());

At that point, poor MyMethod has a parameter which is meant to be of type SomeObject, but is actually of type object. This would be a Very Bad Thing, so the compiler stops it from happening.

Does that all make more sense?

like image 132
Jon Skeet Avatar answered Sep 28 '22 21:09

Jon Skeet


Arguments are contravariant, return types are covariant. If the delegate were to be called with an object that is not an instance of SomeObject, you'd have a typing error. On the other hand, returning SomeObject from a routine wrapped in a delegate that returns object is fine.

like image 36
Jeffrey Hantin Avatar answered Sep 28 '22 19:09

Jeffrey Hantin