Variance in Generic Interfaces (C# and Visual Basic)

Variance support enables a wider range of implicit conversions from one generic interface type to a related generic interface type or from a type that implements one generic interface to a type that implements a related generic interface. The following interfaces are variant:

By using covariance, you can enable a generic interface that has type parameter A to be converted to the same interface with type parameter B if an implicit reference conversion exists from A to B. To illustrate the covariance feature, consider the generic interfaces IEnumerable<Object> and IEnumerable<String> (IEnumerable(Of Object) and IEnumerable(Of String) in Visual Basic). Because the String type is derived from Object, you might expect to be able to use a sequence of strings in place of a sequence of objects. However, without covariance, IEnumerable<String> isn't implicitly convertible to IEnumerable<Object>.

In earlier versions of the .NET Framework, the following code causes a compilation error in C# and in Visual Basic when Option Strict is on. However, now that the IEnumerable interface is covariant, you can use the strings variable in place of the objects variable, as the example shows.

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

Contravariance is like covariance except that it extends convertibility in the opposite direction. For example, IEqualityComparer<Object> is implicitly convertible to IEqualityComparer<String>. To illustrate contravariance, assume that you've created a BaseComparer class to compare instances of the BaseClass class. The BaseComparer class implements the IEqualityComparer<BaseClass> interface. Because the IEqualityComparer interface is contravariant, you can use BaseComparer to compare instances of classes that inherit from the BaseClass class, as the following code example shows.

// Simple hierarchy of classes. 
class BaseClass { }
class DerivedClass : BaseClass { }

// Comparer class. 
class BaseComparer : IEqualityComparer<BaseClass> 
{
    public int GetHashCode(BaseClass baseInstance)
    {
        return baseInstance.GetHashCode();
    }
    public bool Equals(BaseClass x, BaseClass y)
    {
        return x == y;
    }
}
class Program
{
    static void Test()
    {
        IEqualityComparer<BaseClass> baseComparer = new BaseComparer();

        // Implicit conversion of IEqualityComparer<BaseClass> to  
        // IEqualityComparer<DerivedClass>.
        IEqualityComparer<DerivedClass> childComparer = baseComparer;
    }
}

For more examples, see Using Variance in Interfaces for Generic Collections (C# and Visual Basic).

Variance in generic interfaces is supported only for type arguments that are reference types. Value types don't support variance. For example, IEnumerable<int> can't be implicitly converted to IEnumerable<object> because integers are represented by a value type.

IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler errror, 
// because int is a value type. 
// IEnumerable<Object> objects = integers;

It's important to remember that generic classes and structs that implement variant interfaces are still invariant. For example, List implements the covariant interface IEnumerable. You can convert List<String> to IEnumerable<Object>, but you can't convert List<String> to List<Object>. The following code example illustrates this point.

// The following line generates a compiler error 
// because classes are invariant. 
// List<Object> list = new List<String>(); 

// You can use the interface object instead.
IEnumerable<Object> listObjects = new List<String>();
Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft