泛型接口中的变体(C# 和 Visual Basic)

.NET Framework 4 引入了对多种现有泛型接口的变体支持。 变体支持允许对实现这些接口的类进行隐式转换。 下列接口现在为变体:

协变允许方法具有与接口的泛型类型参数所定义的返回类型相比,派生程度更大的返回类型。 为展示协变功能,请考虑以下泛型接口:IEnumerable<Object> 和 IEnumerable<String>(在 Visual Basic 中分别为 IEnumerable(Of Object) 和 IEnumerable(Of String))。 IEnumerable<String>(在 Visual Basic 中为 IEnumerable(Of String))接口不继承 IEnumerable<Object>(在 Visual Basic 中为 IEnumerable(Of Object))接口。 但是,String 类型会继承 Object 类型,在某些情况下,您可能希望为这些接口互相指派彼此的对象。 以下代码示例中演示了这一点。

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;

在 .NET Framework 早期版本中,在 Option Strict On 条件下,此代码会导致 C# 和 Visual Basic 中出现编译错误。 但是现在,您可以使用 strings 代替 objects,如上例所示,因为 IEnumerable<T> 接口为协变接口。

逆变允许方法具有与接口的泛型形参所指定的实参类型相比,派生程度更小的实参类型。 为展示逆变功能,假设您已创建 BaseComparer 类来比较 BaseClass 类的实例。 BaseComparer 类实现 IEqualityComparer<BaseClass>(在 Visual Basic 中为 IEqualityComparer(Of BaseClass))接口。 因为 IEqualityComparer<T> 接口现在为逆变接口,所以您可以使用 BaseComparer 来比较继承 BaseClass 类的类的实例。 以下代码示例中演示了这一点。

' Simple hierarchy of classes.
Class BaseClass
End Class

Class DerivedClass
    Inherits BaseClass
End Class

' Comparer class.
Class BaseComparer
    Implements IEqualityComparer(Of BaseClass)

    Public Function Equals1(ByVal x As BaseClass,
                            ByVal y As BaseClass) As Boolean _
                            Implements IEqualityComparer(Of BaseClass).Equals
        Return (x.Equals(y))
    End Function

    Public Function GetHashCode1(ByVal obj As BaseClass) As Integer _
        Implements IEqualityComparer(Of BaseClass).GetHashCode
        Return obj.GetHashCode
    End Function
End Class
Sub Test()
    Dim baseComparer As IEqualityComparer(Of BaseClass) = New BaseComparer
    ' Implicit conversion of IEqualityComparer(Of BaseClass) to 
    ' IEqualityComparer(Of DerivedClass).
    Dim childComparer As IEqualityComparer(Of DerivedClass) = baseComparer
End Sub
// 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;
    }
}

有关更多示例,请参见在泛型集合的接口中使用变体(C# 和 Visual Basic)

只有引用类型才支持使用泛型接口中的变体。 值类型不支持变体。 例如,无法将 IEnumerable<int>(在 Visual Basic 中为 IEnumerable(Of Integer))隐式转换为 IEnumerable<object>(在 Visual Basic 中为IEnumerable(Of Object)),因为整数由值类型表示。

Dim integers As IEnumerable(Of Integer) = New List(Of Integer)
' The following statement generates a compiler error
' with Option Strict On, because Integer is a value type.
' Dim objects As IEnumerable(Of Object) = integers
IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler errror,
// because int is a value type.
// IEnumerable<Object> objects = integers;

此外还应记住,实现变体接口的类仍是固定类。 例如,虽然 List<T> 实现协变接口 IEnumerable<T>,但无法将 List<Object> 隐式转换为 List<String>(在 Visual Basic 中为将 List(Of Object) 转换为 List(Of String))。 下面的代码示例中阐释了这一点。

' The following statement generates a compiler error
' because classes are invariant.
' Dim list As List(Of Object) = New List(Of String)

' You can use the interface object instead.
Dim listObjects As IEnumerable(Of Object) = New List(Of String)
// 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>();

请参见

参考

在泛型集合的接口中使用变体(C# 和 Visual Basic)

概念

创建变体泛型接口(C# 和 Visual Basic)

泛型接口

委托中的变体(C# 和 Visual Basic)