【问题标题】:c# object interface return type covariance [closed]c#对象接口返回类型协方差
【发布时间】:2017-05-15 12:26:05
【问题描述】:

C# 编译器:

错误 CS0738:Field<T>' does not implement interface memberField.Value.get' 和最佳实现候选 Field<T>.Value.get' return typeT' 与接口成员返回类型“对象”不匹配

public interface Field
{
   object Value {get;}
}

public class MyField<T> : Field
{
   T _value;
   public T Value
   {
      get
      {
         return _value;
      }
   }
}

为什么? List 扩展了 Microsoft 类中的 List,但我作为用户(复制相同的设计模式)不允许这样做吗?为什么?

尝试 where T: object 也会产生编译器错误...

我该如何解决这个问题?

关于同一主题的其他 1.000.000 个线程,说:
blablabla, '返回类型协方差', blablabla, '你不能'。

他们没有就如何编译这个野兽提出解决方案或变通方法。 要求:
1)Field是一个不能接受泛型的接口。名为“unity”的邪恶框架禁止泛型。
2)“实现字段”具有通用T的字段

【问题讨论】:

  • 旁注:为什么将字段 _value 设为公开?这违背了封装字段的目的......使其私有
  • C# 编译器爱你,希望你安全高效,因此有时它会阻止你做危险的、非生产性的事情。就像你妈妈不让你在屋顶上骑自行车一样,即使那样会很棒。
  • List&lt;T&gt; 没有什么特别之处。这是一个普通的类,由对编译器内部没有特殊访问权限的人编写,编译器对它没有什么特别的。如果你想知道List&lt;T&gt;的作者是如何实现IList的,可以阅读源码。
  • 它叫做Explicit Interface Implementation,正如你所见,它既不是特别的,也不是没有提到的MS。
  • 我投票决定将此问题作为离题结束,因为 "your question is just a rant in disguise: '........ sucks, am I right?'"

标签: c# generics types covariance covariant-return-types


【解决方案1】:
public class Field<T> : Field
{
   T _value;

   //specific interface implementation
   object Field.Value
   {
     get
     {
        return _value;
     }
   }

   public T Value
   {
      get
      {
         return _value;
      }
   }
}

【讨论】:

    【解决方案2】:

    您可以显式地实现接口。 https://msdn.microsoft.com/en-us/library/ms173157.aspx

    IEnumerable 和通用IEnumerable&lt;T&gt; 的非通用版本上使用相同的模式

    您也可以这样做并拥有通用接口。

    public interface Field
    {
        object Value { get; }
    }
    
    public interface Field<T> : Field
    {
        new T Value { get; }
    }
    
    public class MyField<T> : Field<T>
    {
        public T Value { get; } // generic
    
        object Field.Value => Value; // non generic
    }
    

    现在,如果您手头有Field&lt;T&gt;,您可以愉快地使用T。如果你有Field,你会得到对象形式的值T

    【讨论】:

    • 太棒了!我正在删除我的答案,这要好得多! +1!
    • 最好用new 标记ValueField&lt;T&gt; 版本,以表明隐藏是故意的。
    • 为什么 Field 接口继承自 Field ? MyField : Field, Field 不是更好吗?然后你不要隐藏继承。
    • @Nyranith:可以说这会更好,但不是因为任何“隐藏”继承。而是:通过从Field 继承,Field&lt;T&gt; 的作者要求所有实现接口的类都执行实现Value 的两个版本的技巧,这既繁琐又烦人。但是请注意,在基类库中,IEnumerator&lt;T&gt; 确实继承自 IEnumerator,所以这种事情确实有一些先例。
    【解决方案3】:

    我不确定这是否正是您想要的。但是如果你的界面不能是通用的,那么这就是可行的。

    public interface Field
    {
       object Value {get;}
    }
    
    public class MyField<T> : Field
    {
       public T _value;
    
       public T MyTypedValue
       {
           get 
           { 
               return _value; 
           }
       }
    
       public object Value
       {
           get
           {
              return _value;
           }
       }
    }
    

    【讨论】:

    • 你很接近,我希望 MyTypedValue 也与 Value 方法共享相同的名称
    【解决方案4】:
    public Object Value
       {
          get
          {
             return _value;
          }
       }
    

    也许你需要这个。因为每种数据类型都继承 Object 但反之亦然。我想这就是协方差问题来的原因。

    【讨论】:

    • 好消息,它可以编译!!!但它污染了我的命名空间。尝试同时使用这两种方法会导致:错误 CS0102: 'Field' already contains a definition for `Value'
    【解决方案5】:

    你没有在界面中使用模板类型,而是使用对象。试试这个吧:

     interface Field<T>
        {
            T Value { get; }
        }
    
    public class MyField<T> : Field<T>
        {
            private T _value;
            public T Value
            {
                get
                {
                    return _value;
                }
            }
        }
    

    【讨论】:

    • OP 表示他的限制之一是接口不能支持泛型
    • 那么 Field 接口将不得不扩展 Field 导致相同的编译错误。
    猜你喜欢
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-29
    • 2021-03-21
    • 1970-01-01
    相关资源
    最近更新 更多