我试图理解这一点,但我没有从搜索中得到任何适当的结果。
在 C# 4 中,我可以做到
public interface IFoo<out T>
{
}
这与
public interface IFoo<T>
{
}
我所知道的是out
使通用参数协变(??)。<out T>
有人可以举例说明零件的用法吗?还有为什么只适用于接口和委托而不适用于类?
对不起,如果它是重复的,如果是,请关闭它。
有人可以举例说明 out T 部分的用法吗?
当然。IEnumerable<T>
是协变的。这意味着你可以这样做:
static void FeedAll(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals) animal.Feed();
}
...
IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
FeedAll(giraffes);
“协变”是指在泛型类型中保留了类型实参的赋值兼容关系。Giraffe
是赋值与 兼容Animal
,因此该关系保留在构造类型中:IEnumerable<Giraffe>
赋值与IEnumerable<Animal>
.
为什么只适用于接口和委托而不适用于类?
类的问题在于类往往具有可变字段。让我们举个例子。假设我们允许这样做:
class C<out T>
{
private T t;
好的,现在在继续之前仔细考虑这个问题。可以C<T>
在构造函数之外使用任何方法将字段设置为t
默认值以外的值吗?
因为它必须是类型安全的,C<T>
所以现在不能有以 T 作为参数的方法;T 只能退货。那么谁设置 t,他们从哪里获得设置它的值?
协变类类型只有在类是不可变的情况下才真正起作用。而且我们没有在 C# 中创建不可变类的好方法。
我希望我们这样做,但我们必须接受我们提供的 CLR 类型系统。我希望将来我们可以更好地支持不可变类和协变类。
如果您对此功能感兴趣,请考虑阅读我关于我们如何设计和实现该功能的长系列。从底部开始:
https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/
如果我们谈论的是通用方差:
协方差是关于从操作返回给调用者的值。
逆变它是相反的,它是关于调用者传递的值:
据我所知,如果类型参数仅用于输出,您可以使用 out。但是,如果该类型仅用于输入,则可以使用 in。这很方便,因为编译器无法确定您是否可以记住哪种形式称为协变,哪种形式称为逆变。如果在声明类型后不显式声明它们,则相关类型的转换是隐式可用的。
类中没有方差(协方差或逆变),因为即使您有一个仅将类型参数用于输入(或仅将其用于输出)的类,您也无法指定 in 或 out 修饰符。只有接口和委托可以有变体类型参数。首先,CLR 不允许这样做。从概念的角度来看,接口代表了一种从特定角度看待对象的方式,而类是更实际的实现类型。
这意味着如果你有这个:
class Parent { }
class Child : Parent { }
那么 的实例IFoo<Child>
也是 的实例IFoo<Parent>
。