我试图理解这一点,但我没有从搜索中得到任何适当的结果。
在c#4中,我可以做到
public interface IFoo<out T>
{
}
这与
有什么不同 public interface IFoo<T>
{
}
我所知道的是out
使通用参数协变(??)。
有人可以用一个例子解释<out T>
部分的用法吗?另外,为什么只适用于接口和代理而不适用于类?
很抱歉,如果它是重复的,请将其关闭,如果是的话。
答案 0 :(得分:40)
有人可以通过示例解释out T部分的用法吗?
不确定。 IEnumerable<T>
是协变的。这意味着你可以这样做:
static void FeedAll(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals) animal.Feed();
}
...
IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
FeedAll(giraffes);
“Covariant”表示类型参数的赋值兼容性关系保留在泛型类型中。 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/
答案 1 :(得分:5)
如果我们谈论通用差异:
协方差是关于从操作返回给调用者的值。
Contravariance 它是相反的,它是关于调用者传递的值:
据我所知,如果类型参数仅用于输出,则可以使用out。但是,如果类型仅用于输入,则可以使用。这是方便的,因为编译器无法确定您是否能够记住哪种形式称为协方差,哪种形式称为逆变。如果您在声明类型后未明确声明它们,则可以使用隐式来获得相关的转换类型。
类中没有方差(协方差或逆变),因为即使你有一个只使用type参数输入的类(或者只用它来输出),你 无法指定in或out修饰符。只有接口和委托可以具有变体类型参数。首先,CLR不允许它。从概念的角度来看,Interfaces表示从特定角度查看对象的方式,而类更多是实际实现类型。
答案 2 :(得分:3)
这意味着如果你有这个:
class Parent { }
class Child : Parent { }
然后IFoo<Child>
的实例也是IFoo<Parent>
的实例。