协方差通用参数

本文关键字:参数 方差通 | 更新日期: 2023-09-27 18:00:31

我试图理解这一点,但我没有从搜索中得到任何合适的结果。

在C#4中,我可以进行

    public interface IFoo<out T>
    {
    }

这与有何不同

    public interface IFoo<T>
    {
    }

我只知道out使一般参数协变(??)。有人能举例说明<out T>部分的用法吗?为什么只适用于接口和委托,而不适用于类?

如果它是重复的,很抱歉,如果是,请按原样关闭它。

协方差通用参数

有人能举例说明out T部分的用法吗?

当然。CCD_ 3是协变的。这意味着你可以这样做:

static void FeedAll(IEnumerable<Animal> animals) 
{
    foreach(Animal animal in animals) animal.Feed();
}
...
 IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
 FeedAll(giraffes);

"协变"意味着类型参数的赋值兼容性关系保留在泛型类型中。GiraffeAnimal是赋值兼容的,因此在构造的类型中保留了这种关系: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或out修饰符。只有接口和委托可以具有变体类型参数。首先,CLR不允许这样做。从概念的角度来看,接口代表了从特定角度看待对象的一种方式,而类则是更多的实际实现类型。

这意味着如果你有这个:

class Parent { } 
class Child : Parent { }

则CCD_ 11的实例也是CCD_ 12的实例。