示例公式:若 A ≤ B,则 T 可协变为 T。
// 协变示例
public interface ICoVariant
{
T GetItem();
}
public class BaseClass { }
public class DerivedClass : BaseClass { }
// 使用协变的接口
ICoVariant baseInstance = new CoVariant();
BaseClass item = baseInstance.GetItem(); // 隐式转换,获取 DerivedClass 实例
逆变则允许在泛型委托或泛型接口中进行子类到父类的隐式转换。如果类型 A 是类型 B 的子类型(A ≤ B),则支持逆变的情况下,泛型类型参数 T 可以被隐式转换为 T。逆变为我们提供了更多的灵活性,允许我们传递更具体类型的对象给接受更抽象类型的泛型接口或委托。
示例公式:若 A ≤ B,则 T 可逆变为 T。
// 逆变示例
public interface IContraVariant
{
void PrintItem(T item);
}
public class BaseClass { }
public class DerivedClass : BaseClass { }
// 使用逆变的接口
IContraVariant derivedInstance = new ContraVariant();
derivedInstance.PrintItem(new DerivedClass()); // 隐式转换,接受 BaseClass 实例
继承关系与类型转换是协变和逆变的基础。在协变的情况下,随着类型的派生程度增加,泛型类型参数的继承关系也得到了保持。而在逆变的情况下,派生程度更大的类型可以被隐式地转换为派生程度更小的类型。这些关系可以用公式表示如下:
这些公式强调了在协变和逆变中,类型转换的方向是根据类型的继承关系而变化的。
协变允许我们在泛型委托中进行父类到子类的隐式转换。请参考下面的示例:
public delegate T DelegateFuncA(); //支持协变
DelegateFuncA funcObject = null;
DelegateFuncA funcString = null;
funcObject = funcString; //协变
在这个例子中,DelegateFuncA
声明了一个支持协变的泛型委托。通过将 funcString
赋值给 funcObject
,我们实现了从 string
到 object
的协变转换。这种灵活性可以在一些场景中提高代码的可读性和可维护性。
逆变允许我们在泛型委托中进行子类到父类的隐式转换。请参考下面的示例:
public delegate void DelegateFuncB(T param); //支持逆变
DelegateFuncB actionObject = null;
DelegateFuncB actionString = null;
actionString = actionObject; //逆变
在这个示例中,DelegateFuncB
是一个支持逆变的泛型委托。通过将 actionObject
赋值给 actionString
,我们实现了从 object
到 string
的逆变转换。逆变为我们提供了更多的灵活性,使得我们能够更容易地传递具有更具体类型的方法给接受更抽象类型的委托。
协变在泛型接口中的应用同样是非常有意义的。请参考下面的示例:
public delegate T InterfaceFuncA(); //支持协变
InterfaceFuncA interfaceFuncObject = null;
InterfaceFuncA interfaceFuncString = null;
interfaceFuncObject = interfaceFuncString; //协变
在这个例子中,我们使用支持协变的泛型接口 InterfaceFuncA
。通过将 interfaceFuncString
赋值给 interfaceFuncObject
,我们实现了从 string
到 object
的协变转换。
逆变同样可以在泛型接口中发挥作用。请参考下面的示例:
public delegate void InterfaceFuncB(T param); //支持逆变
InterfaceFuncB interfaceFuncObjectB = null;
InterfaceFuncB interfaceFuncStringB = null;
interfaceFuncStringB = interfaceFuncObjectB; //逆变
在这个例子中,我们使用支持逆变的泛型接口 InterfaceFuncB
。通过将 interfaceFuncObjectB
赋值给 interfaceFuncStringB
,我们实现了从 object
到 string
的逆变转换。
逆变同样可以在数组中发挥作用,使得派生程度更大的类型的数组能够隐式转换为派生程度更小的类型的数组。请参考下面的示例:
// 数组的逆变使派生程度更大的类型的数组能够隐式转换为派生程度更小的类型的数组。
object[] array = new string[10];
array[0] = 10;
在这个示例中,我们创建了一个 object
类型的数组,但实际上它指向的是一个 string
类型的数组。这是数组逆变的一个实际应用,使得我们能够更灵活地处理不同派生程度的数组类型。