【问题标题】:polymorphism for properties specified by interfaces由接口指定的属性的多态性
【发布时间】:2010-09-08 16:53:32
【问题描述】:

为什么这不起作用?

 public class ClassOptions {}

 public interface Inode {
    ClassOptions Options {get;}
 }            

public class MyClass : Inode {
  public ClassOptions Options { get; set; }
}           

public class ClassDerivedOptions : ClassOptions {
}

public class MyDerivedClass : Inode {
    public ClassDerivedOptions Options { get; set; } << does not implement INode...
}

[ 编译器消息告诉我为什么它会中断,但我想知道编译器为什么不让它通过的原因 - 如果有任何解决方法? - 谢谢]

【问题讨论】:

标签: c# c#-4.0 polymorphism


【解决方案1】:

它不起作用,因为 INode 接口显式调用 ClassOptions 类型的 Options 属性。 C# 不支持返回类型协方差(这是您在本例中所要求的)。

对于它的价值,Microsoft Connect 上还有一个专门针对返回类型协方差的语言功能请求:

Need covariant return types in C# / all .NET languages

如果您查看该页面,他们还提到常见的解决方法是使用显式接口实现:

public class MyDerivedClass : INode
{
    public ClassDerivedOptions Options { get; set; }
    public ClassOptions INode.Options { get { return Options; } }
}

【讨论】:

    【解决方案2】:

    正如 Justin 所说,您想要的功能称为“返回类型协方差”,它在 C# 中不受支持,或者就此而言,在 CLR 类型系统中不受支持。

    虽然经常被要求,但此功能极不可能 (*) 很快就会实施。由于 CLR 不支持它,为了实现它,我们只需生成所有为您执行呼叫转发的辅助方法。由于您已经可以使用少量代码“手动”执行此操作,因此编译器为您执行此操作几乎没有增加价值。 (还有as another question today notes, people sometimes get confused or irritated when the compiler generates a method to do interface forwarding on your behalf。)

    别误会我的意思;我可以看到它是如何派上用场的,并且我已经在 C++ 中使用了这个特性。但是每次它出现在 C# 程序中时,我发现我可以很容易地解决它的缺失。

    (*) 当然,五年前我会对命名参数和可选参数说同样的话,而现在它们在 C# 4 中。 有可能出现一个不太可能的特性实施,但需求必须相当高。

    【讨论】:

      【解决方案3】:

      它不起作用,因为接口定义了合同,并且当您实现此合同时,方法签名必须完全匹配。一种可能的解决方法是使用通用接口:

      public class ClassOptions 
      { }
      
      public class ClassDerivedOptions : ClassOptions 
      { }
      
      public interface INode<T> where T : ClassOptions
      {
          T Options { get; }
      }            
      
      public class MyClass : INode<ClassOptions> 
      {
          public ClassOptions Options { get; set; }
      }           
      
      public class MyDerivedClass : INode<ClassDerivedOptions>
      {
          public ClassDerivedOptions Options { get; set; }
      }
      

      【讨论】:

      • 感谢您的工作,它看起来比其他人建议的更优雅。
      【解决方案4】:

      处理这种情况的标准方法是显式实现接口:

      public class MyDerivedClass : Inode {
      
          // New, more specific version:
          public ClassDerivedOptions Options { get; set; }
      
          // Explicit implementation of old, less specific version:
          ClassOptions Inode.Options
          {
              get { return Options; }
          }
      }
      

      这就是大多数旧的IList 实现在泛型之前的工作方式,例如:指定更具体的T this[int index] 属性,然后显式实现object IList.this[int index],当set 被调用时抛出异常类型错误。

      在您发布的示例代码中,您甚至需要明确的set,因为它不是Inode 接口的成员。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-02
        • 2011-02-20
        • 2016-09-12
        • 2017-11-28
        • 2013-05-17
        • 2011-05-04
        • 1970-01-01
        • 2010-09-20
        相关资源
        最近更新 更多