提问者:小点点

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


我正在使用。NET framework,我真的希望能够制作一个自定义类型的页面,我的所有网站都使用。 当我试图从控件访问页面时,问题就来了。 我希望能够返回我的特定类型的页面,而不是默认页面。 有什么办法可以做到这一点吗?

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

public class MyControl : Control
{
    public MyPage Page { get; set; }
}

共3个答案

匿名用户

更新:这个答案写于2011年。 在人们为C#提出返回类型协方差二十年之后,看起来它终于要实现了; 我相当惊讶。 请参阅https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0//底部的公告; 我相信细节会跟进的。

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

返回类型协方差是用返回更特定类型的基类方法重写返回较不特定类型的基类方法的地方:

abstract class Enclosure
{
    public abstract Animal Contents();
}
class Aquarium : Enclosure
{
    public override Fish Contents() { ... }
}

这是安全的,因为通过围栏购买物品的消费者希望看到的是一只动物,而水族馆承诺不仅要满足这一要求,而且还要做出一个更严格的承诺:动物永远是鱼。

C#中不支持这种协方差,也不太可能支持这种协方差。 CLR不支持它。 (它由C++和CLR上的C++/CLI实现支持;它通过生成下面我建议的那种神奇的助手方法来实现。)

(有些语言也支持形参类型的逆变--您可以用一个带动物的方法来重写带鱼的方法。同样地,契约得到了实现;基类要求处理任何鱼,而派生类承诺不仅要处理鱼,还要处理任何动物。类似地,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() { ... }
}

现在,您既可以重写虚拟方法,又可以在使用编译时类型水族馆时获得更强的键入功能。

匿名用户

对于接口,我通过显式地实现接口来解决这个问题:

public interface IFoo {
  IBar Bar { get; }
}
public class Foo : IFoo {
  Bar Bar { get; set; }
  IBar IFoo.Bar => Bar;
}

匿名用户

将其放置在MyControl对象中会起作用:

 public new MyPage Page {get return (MyPage)Page; set;}'

您不能重写该属性,因为它返回了不同的类型。。。 但你可以重新定义它。

在本例中不需要协方差,因为它相对简单。 您所做的就是从MyPage继承基本对象page。 要返回MyPage而不是Page的任何控件都需要重新定义控件Page属性