Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding delegate contravariance usefulness

So I have a delegate defined as:

public delegate void MyDelegate<T>(T myParameter);

Resharper suggests that I should make T contravariant as follows:

public delegate void MyDelegate<in T>(T myParameter);

Now, I have a hard time understanding what this is good for? I know it prevents me from making T a return type, but other than that, what useful constraints do I get by making T contravariant? That is, when it's time to use the delegate with an instance, what instances can I create with

public delegate void MyDelegate<T>(T myParameter);

that I cannot create with

public delegate void MyDelegate<in T>(T myParameter);
like image 870
AxiomaticNexus Avatar asked Sep 12 '13 19:09

AxiomaticNexus


People also ask

Why is contravariance useful?

This is mainly useful when using already defined standard interfaces. Covariance means that you can use IEnumerable<string> in place where IEnumerable<object> is expected. Contravariance allows you to pass IComparable<object> as an argument of a method taking IComparable<string> .

What is the purpose of covariance and contravariance?

Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types.

What is the difference between covariance and contravariance in delegates?

Covariance permits a method to have return type that is more derived than that defined in the delegate. Contravariance permits a method that has parameter types that are less derived than those in the delegate type.


2 Answers

Here's an instance where if you remove the contravariance in marker it won't compile:

delegate void Callback<in T>(T t);

public Form1()
{
    InitializeComponent();
    Callback<Control> showText = control => MessageBox.Show(control.Text);
    var button = new Button();
    AddButtonClickCallback(button, showText);
    var label = new Label();
    AddLabelClickCallback(label, showText);
}

static void AddButtonClickCallback(Button button, Callback<Button> callback)
{
    button.Click += delegate { callback(button); };
}

static void AddLabelClickCallback(Label label, Callback<Label> callback)
{
    label.Click += delegate { callback(label); };
}

Somewhat contrived, sure, but should at least give you an idea of the kind of things you can't do without it.

Especially think in terms of if AddLabelClickCallback and AddButtonClickCallback were library functions and Callback was a library delegate. If it was defined without contravariance, you'd have to define different delegates showButtonText and showLabelText even though you just want them to do the same thing.

like image 114
Dax Fohl Avatar answered Oct 06 '22 00:10

Dax Fohl


The in keyword on generic allows for implicit conversion to occur. Basically you can assign less derived delegate types to your delegate... Not always useful, read here for more information.

http://msdn.microsoft.com/en-us/library/dd469484.aspx

Example, from MSDN article:

// Contravariant delegate. 
public delegate void DContravariant<in A>(A argument);

// Methods that match the delegate signature. 
public static void SampleControl(Control control)
{ }
public static void SampleButton(Button button)
{ }

public void Test()
{
    // Instantiating the delegates with the methods.
    DContravariant<Control> dControl = SampleControl;
    DContravariant<Button> dButton = SampleButton;

    // You can assign dControl to dButton 
    // because the DContravariant delegate is contravariant.
    dButton = dControl;

    // Invoke the delegate.
    dButton(new Button()); 
}

In that example, the Control will be implicitly converted to Button type, though an exception could occur if the implicit conversion to Button type was not defined in the Button class to allow Control to become Button.

More on implicit conversion definitions: http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx

like image 41
Haney Avatar answered Oct 06 '22 01:10

Haney