我正在尝试理解这个问题,但是在搜索中没有找到合适的结果。
在C# 4中,我可以这样做:
public interface IFoo<out T>
{
}
这个有什么不同之处?
public interface IFoo<T>
{
}
我知道的是out
将泛型参数协变(??)。
有人能用示例解释一下<out T>
的用法吗?还有为什么它只适用于接口和委托,而不适用于类?
如果这是重复的问题,请原谅并将其关闭。
我正在尝试理解这个问题,但是在搜索中没有找到合适的结果。
在C# 4中,我可以这样做:
public interface IFoo<out T>
{
}
这个有什么不同之处?
public interface IFoo<T>
{
}
我知道的是out
将泛型参数协变(??)。
有人能用示例解释一下<out T>
的用法吗?还有为什么它只适用于接口和委托,而不适用于类?
如果这是重复的问题,请原谅并将其关闭。
static void FeedAll(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals) animal.Feed();
}
...
IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
FeedAll(giraffes);
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/
C<T>
有多个字段的类型涉及到T
,它可以有基于另一个字段中的信息设置t
的方法。此外,即使字段只能在构造函数中设置,如果像Tuple<Cat, ToyotaPrius>
这样的东西可以传递给期望Tuple<Animal, Car>
的代码,那将非常有用。我认为协变类的一个更根本的问题是,从Foo<T>
产生的每个不同类都有自己的一组静态变量。如果Foo<T>.Q()
是返回静态字段的实例属性,并且可以有Foo<Animal> it = new Foo<Cat>();
... - supercat如果我们谈论一般性的差异:
协变是关于从操作返回值到调用方的所有内容。
逆变则相反,它是关于由调用者传递值的内容:
据我所知,如果一个类型参数仅用于输出,您可以使用out。然而,如果该类型仅用于输入,则可以使用in。这很方便,因为编译器无法确定您是否记得哪种形式被称为协变,哪种形式被称为逆变。如果不显式声明它们,一旦已声明了类型,相关的转换类型将隐式可用。
类中没有任何协变(包括协变或逆变),因为即使您有一个仅对类型参数进行输入(或仅对其进行输出)的类,也不能指定in或out修饰符。只有接口和委托可以具有变量类型参数。首先CLR不允许这样做。从概念上来说,接口代表了从特定角度观察对象的方式,而类则更多地代表了实际实现类型。
class Parent { }
class Child : Parent { }
那么,IFoo<Child>
的实例也是IFoo<Parent>
的实例。