Covariance and Contravariance (C# and Visual Basic)

[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]

In generic interfaces and delegates, covariance is the ability to use a more derived type than that specified by the generic parameter, whereas contravariance is the ability to use a less derived type. A generic interface or delegate is called variant if its generic parameters can be declared covariant or contravariant.

Starting with .NET Framework 4 and Visual Studio 2010, both C# and Visual Basic support variant generic interfaces and delegates and allow for implicit conversion of generic type parameters. Both languages also enable you to create your own variant interfaces and delegates.

In order to illustrate the covariance feature, consider these generic interfaces: IEnumerable<Object> and IEnumerable<String> (IEnumerable(Of Object) and IEnumerable(Of String) in Visual Basic). The IEnumerable<String> (IEnumerable(Of String) in Visual Basic) interface does not inherit the IEnumerable<Object> (IEnumerable(Of Object) in Visual Basic) interface. However, the String type does inherit the Object type, and in some cases you may want to assign objects of these interfaces to each other, as shown in the following code example.

Dim strings As IEnumerable(Of String) = New List(Of String)
'…
Dim objects As IEnumerable(Of Object) = strings
IEnumerable<String> strings = new List<String>();
//…
IEnumerable<Object> objects = strings;

In earlier versions of the .NET Framework, this code caused a compilation error in C# and in Visual Basic with Option Strict On.

Variance is supported for reference types only, whereas value types do not support variance. For example, IEnumerable<int> (IEnumerable(Of Integer) in Visual Basic) cannot be implicitly converted to IEnumerable<object> (IEnumerable(Of Object) in Visual Basic).

In the previous example, you can use strings instead of objects because the IEnumerable<T> interface is covariant.

To illustrate contravariance, imagine that you have a Windows Forms application in which the MouseClick and KeyDown events for a button are handled identically. However, the MouseClick event uses a delegate that has an argument of the MouseEventArgs type, whereas the KeyDown event uses a delegate that has an argument of the KeyEventArgs type. By using contravariance, you can create just one event handler that accepts a parameter of the EventArgs type. This event handler can handle both events, because the MouseEventArgs and KeyEventArgs types both derive from the EventArgs type. Therefore, you can write the code as shown in the following example.

' Event hander that accepts a parameter of the EventArgs type.
Private Sub MultiHandler(ByVal sender As Object,
                         ByVal e As System.EventArgs)
    Label1.Text = DateTime.Now
End Sub

Private Sub Form1_Load(ByVal sender As System.Object,
    ByVal e As System.EventArgs) Handles MyBase.Load

    ' You can use a method that has an EventArgs parameter,
    ' although the event expects the KeyEventArgs parameter.
    AddHandler Button1.KeyDown, AddressOf MultiHandler

    ' You can use the same method 
    ' for the event that expects the MouseEventArgs parameter.
    AddHandler Button1.MouseClick, AddressOf MultiHandler
End Sub
// Event hander that accepts a parameter of the EventArgs type.
private void MultiHandler(object sender, System.EventArgs e)
{
    label1.Text = System.DateTime.Now.ToString();
}

public Form1()
{
    InitializeComponent();

    // You can use a method that has an EventArgs parameter,
    // although the event expects the KeyEventArgs parameter.
    this.button1.KeyDown += this.MultiHandler;

    // You can use the same method 
    // for the event that expects the MouseEventArgs parameter.
    this.button1.MouseClick += this.MultiHandler;

}

Title

Description

Variance in Generic Interfaces (C# and Visual Basic)

Provides a list of generic interfaces in the .NET Framework and describes how to declare, implement, and extend variant generic interfaces.

Using Covariance and Contravariance in Interfaces for Generic Collections (C# and Visual Basic)

Shows how to use covariance and contravariance in .NET Framework interfaces to convert and compare generic collections.

Variance in Generic Delegates (C# and Visual Basic)

Provides a list of generic delegates in the .NET Framework and describes how to declare, instantiate, and invoke generic delegates.

Using Covariance and Contravariance for Func and Action Generic Delegates (C# and Visual Basic)

Shows how to use covariance and contravariance in .NET Framework delegates to provide more flexibility in matching method signatures.

Covariance and Contravariance in the Common Language Runtime

Describes three features of the common language runtime (CLR) that depend on covariance and contravariance: relaxed delegate binding, covariant and contravariant generic type parameters, and covariance in array assignments.