public class MyPage : Page
{
// My own logic
}
public class MyControl : Control
{
public MyPage Page { get; set; }
}
#1 楼
UPDATE:该答案写于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实现的支持;它是通过生成我在下面建议的那种神奇的辅助方法来实现的。)
(某些语言支持形式参数类型对数同样,您也可以使用采用Animal的方法来覆盖采用Fish的方法;同样,合同也应得到履行;基类要求处理任何Fish,派生类承诺不仅要处理鱼类,但是,任何动物都一样。C#和CLR不支持形式参数类型的自变量。)
解决此限制的方法是执行以下操作:
现在,您既具有覆盖虚拟方法的好处,又具有使用编译时类型的Aquarium时获得更强类型的好处。
评论
完善!我忘了躲藏!
–凯尔·斯莱顿(Kyle Sletten)
11年4月18日在21:38
一如既往的好答案。我们错过了这些答案已有一段时间了。
–德南杰(Dhananjay)
2012年7月20日13:32
是否有理由不支持可在任何地方读取的返回协方差和参数协方差?
– porges
2012年11月14日下午5:19
@EricLippert作为C#分组用户,我一直对“后台”感到好奇,所以我只想问:C#是否考虑过返回类型协方差并且认为ROI太低?我了解时间和bugtet的限制,但是从您的“不可能得到支持”的说法看来,设计团队实际上宁愿不使用该语言。另一方面,Java在Java 5中引入了该语言功能,所以我想知道控制语言设计过程的更大,总体原则之间有什么区别。
–克里斯蒂安·迪亚科内斯库(Cristian Diaconescu)
2012年11月20日10:14
@Cyral:正确;它已列在“中等利率”类别中-这已经有很长时间了!可能会发生,但是我非常怀疑。
–埃里克·利珀特
2015年5月1日23:50
#2 楼
通过接口,我通过显式实现接口来解决它:public interface IFoo {
IBar Bar { get; }
}
public class Foo : IFoo {
Bar Bar { get; set; }
IBar IFoo.Bar => Bar;
}
#3 楼
将其放置在MyControl对象中将起作用: public new MyPage Page {get return (MyPage)Page; set;}'
您无法覆盖该属性,因为它返回了不同的类型...但是您可以重新定义它。
在此示例中,您不需要协方差,因为它相对简单。您要做的就是从
Page
继承基础对象MyPage
。您要返回Control
而不是MyPage
的任何Page
需要重新定义Page
的Control
属性#4 楼
是的,它支持协方差,但是它取决于您要实现的确切目标。我也经常在泛型上使用泛型,这意味着当您执行以下操作时:
class X<T> {
T doSomething() {
}
}
class Y : X<Y> {
Y doSomethingElse() {
}
}
var Y y = new Y();
y = y.doSomething().doSomethingElse();
不要“丢掉”您的类型。
#5 楼
这是即将发布的C#9.0(.Net 5)的一项功能,您可以立即下载其预览版本。以下代码现已成功构建(无提示:
error CS0508: 'Tiger.GetFood()': return type must be 'Food' to match overridden member 'Animal.GetFood()'
) class Food { }
class Meat : Food { }
abstract class Animal {
public abstract Food GetFood();
}
class Tiger : Animal {
public override Meat GetFood() => default;
}
class Program {
static void Main() => new Tiger();
}
#6 楼
我还没有尝试过,但是没有用吗?YourPageType myPage = (YourPageType)yourControl.Page;
评论
是的,确实如此。我只想尝试避免在整个地方投射。
–凯尔·斯莱顿(Kyle Sletten)
2011年4月18日在21:28
#7 楼
是。有多种方法可以执行此操作,而这只是一个选择:您可以使页面实现一些自定义接口,该接口公开一个名为“ GetContext”的方法或类似的方法,并返回您的特定信息。然后,您的控件可以简单地请求页面并进行强制转换:
#8 楼
您可以通过上级父树从任何控件访问页面。那就是myParent = this;
while(myParent.parent != null)
myParent = myParent.parent;
*没有编译或测试。
或在当前上下文中获取父页面(取决于您的版本)。
然后我想要做的是:我创建一个接口,该接口带有要在控件中使用的功能(例如IHostingPage)。
然后我强制转换父页面“ IHostingPage host =(IHostingPage)Parent;”而且我已经准备好从控件中调用所需页面上的函数。
#9 楼
我将以这种方式进行操作:class R {
public int A { get; set; }
}
class R1: R {
public int B { get; set; }
}
class A
{
public R X { get; set; }
}
class B : A
{
private R1 _x;
public new R1 X { get => _x; set { ((A)this).X = value; _x = value; } }
}
评论
利用泛型可能复制c#协变量返回类型