【问题标题】:implementing contravariance in interface in c#在 C# 中的接口中实现逆变
【发布时间】:2018-05-21 17:59:45
【问题描述】:

我浏览了很多博客来了解逆变,我了解的越多,我就越困惑。

我的问题是,假设我有一个接口和实现如下

interface ICovariant<in T>
    {
        void add(T _object);
    }
    public class sample<T> : ICovariant<T>
    {
        List<T> lists = new List<T>();
        public void add(T _object)
        {
            lists.Add(_object);
        }
    }
    public class baseClass
    {
        public string name { get; set; }
        public void print()
        {
            Console.WriteLine("one method");
        }
    }
    public class derivedClass : baseClass
    {
        public string address { get; set; }
        public void print()
        {
            Console.WriteLine("one more method");
        }
    }

我像这样实现逆变

ICovariant<derivedClass> derivedClass = new sample<baseClass>();

在上面的行中,我可以在最衍生的类上定义最小的衍生类,但是当我这样做时,我得到了一个错误

derivedClass.add(new baseClass());

为什么会报错?

  1. 我在接口中定义时提到了 T 作为逆变。
  2. 当我能够初始化具有最少继承类型的示例类时,为什么我不能在调用 add 方法时做同样的事情。

我错过了什么

【问题讨论】:

  • ICovariant 不是协变的。将非协变接口命名为 ICovariant 是非常卑鄙的。

标签: c# c#-4.0 contravariance


【解决方案1】:

当我能够用最少继承类型初始化示例类时,为什么我不能在调用 add 方法时做同样的事情?

因为您将对象转换为ICovariant&lt;derivedClass&gt;ICovariant&lt;derivedClass&gt; 有一个 add 方法,它只接受 derivedClass 实例,而 baseClass 不是 derivedClass 实例。如果您没有将sample&lt;baseClass&gt; 转换为ICovariant&lt;derivedClass&gt;,而是将其保留为sample&lt;baseClass&gt;(甚至ICovariant&lt;baseClass&gt;),那么add 方法将接受baseClass,而不是derivedClass,您可以将任何baseClass 实例传递给它。

【讨论】:

  • 我在初始化过程中提到了接口是逆变的,就像这个 ICovariant 那么理想情况下我应该能够同时使用这两个类吗?
  • @LijinDurairaj 是的,接口是逆变的。因为它是逆变的,所以允许sample&lt;baseClass&gt; 分配给ICovariant&lt;derivedClass&gt; 类型的变量。但是通过选择利用这种逆变性,你限制了你可以用那个实例做什么(通过接口)。这就是它允许您进行转换的原因,因为sample&lt;baseClass&gt; 可以完成ICoveriant&lt;derivedClass&gt; 可以做的所有事情以及更多,因此通过将其转换为ICoveriant&lt;derivedClass&gt;,您只是删除 功能上,没关系。
  • @LijinDurairaj 如果您希望能够将baseClassderivedClass 传递给add,那么您需要有一个ICovariant&lt;baseClass&gt;,(或者只是一个sample&lt;baseClass&gt; ) 不是ICovariant&lt;derivedClass&gt;。一个ICovariant&lt;derivedClass&gt; 不能接受任何baseClass,它只能接受derivedClass 实例。
  • 那么在这种情况下逆变有什么用呢?
  • @LijinDurairaj 在这种情况下,没有。对于您正在尝试做的事情,重要的是您利用它。如果您想要确保人们只能添加派生类型,并且想要禁止人们添加基类型对象,那么它会很有用。
猜你喜欢
  • 2011-10-26
  • 1970-01-01
  • 2021-09-18
相关资源
最近更新 更多