C#是否支持返回类型协方差?

Kyl*_*ten 76 c# covariance

我正在使用.NET框架,我真的希望能够创建一个我所有网站都使用的自定义类型的页面.当我尝试从控件访问页面时出现问题.我希望能够返回我的特定类型的页面而不是默认页面.有没有办法做到这一点?

public class MyPage : Page
{
    // My own logic
}

public class MyControl : Control
{
    public MyPage Page { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 150

听起来你想要的是返回类型协方差.C#不支持返回类型协方差.

返回类型协方差是覆盖基类方法的地方,该方法返回一个不太具体的类型,返回更具体的类型:

abstract class Enclosure
{
    public abstract Animal Contents();
}
class Aquarium : Enclosure
{
    public override Fish Contents() { ... }
}
Run Code Online (Sandbox Code Playgroud)

这是安全的,因为通过Enclosure的内容的消费者期望动物,并且水族馆承诺不仅满足该要求,而且,做出更严格的承诺:动物总是鱼.

C#不支持这种协方差,并且不太可能支持.CLR不支持它.(它受C++和CLR上的C++/CLI实现支持;它通过生成我在下面建议的类型的魔法辅助方法来实现.)

(有些语言也支持形式参数类型的逆转 - 您可以覆盖一个方法,该方法使用带有Animal的方法获取Fish.同样,合同得到满足;基类要求处理任何Fish,并且派生class承诺不仅处理鱼类,而且处理任何动物.同样,C#和CLR不支持形式参数类型的逆转.)

解决此限制的方法是执行以下操作:

abstract class Enclosure
{
    protected abstract Animal GetContents();
    public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
    protected override Animal GetContents() { return this.Contents(); }
    public new Fish Contents() { ... }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以获得覆盖虚拟方法的好处,并在使用编译时类型Aquarium时获得更强的输入.

  • @EricLippert作为一个C#群体,我总是对"后台"感到好奇,所以我只想问:C#的返回类型协方差是否曾被考虑过,并且被认为投资回报率太低?我理解时间和bugdet约束,但从你"不太可能得到支持"的声明来看,听起来设计团队实际上并不是在语言中没有这个.另一方面,Java在Java 5中引入了这种语言特性,所以我想知道管理语言设计过程的更大,更重要的原则是什么区别. (24认同)
  • @Cyral:正确; 它位于"温和兴趣"桶的列表中 - 这是它已经存在很长时间了!它可能发生,但我非常怀疑. (6认同)
  • 一如既往的好答案.我们暂时错过了那些答案. (3认同)
  • 完善!我忘了躲藏! (2认同)
  • 有没有理由不支持返回协方差和参数可能在任何地方读取? (2认同)
  • @Porges:我们不需要为*not*支持功能提供理由.功能很昂贵,默认情况下不实现.只有当功能被考虑,设计,指定,实施,测试并运送给客户时,它们才能实现. (2认同)
  • 这似乎正在考虑用于C#7。https://github.com/dotnet/roslyn/issues/2136 (2认同)
  • 可悲的是,该功能没有将其纳入C#7。但是跟踪它仍然存在问题:https://github.com/dotnet/roslyn/issues/357 (2认同)

Che*_*les 5

通过接口,我通过显式实现接口来解决它:

public interface IFoo {
  IBar Bar { get; }
}
public class Foo : IFoo {
  Bar Bar { get; set; }
  IBar IFoo.Bar => Bar;
}
Run Code Online (Sandbox Code Playgroud)