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)
{}
}
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With