题
据我所知,无法在C#2.0中执行以下操作
public class Father
{
public virtual Father SomePropertyName
{
get
{
return this;
}
}
}
public class Child : Father
{
public override Child SomePropertyName
{
get
{
return this;
}
}
}
我通过在派生类中创建<!> quot; new <!> quot;来解决问题,但当然这不是多态的。
public new Child SomePropertyName
2.0中有什么解决方案吗? 3.5中解决此问题的任何功能如何?
解决方案
由于类型安全问题,这在任何.NET语言中都是不可能的。在类型安全的语言中,您必须为返回值和参数的逆变提供协方差。拿这个代码:
class B {
S Get();
Set(S);
}
class D : B {
T Get();
Set(T);
}
对于Get
方法,协方差意味着T
必须是S
或从D
派生的类型。否则,如果您对类型为B
的对象的引用存储在变量类型B.Get()
中,则当您调用Set
时,您将无法获得可表示为B.Set(X)
的对象,从而破坏类型系统
对于X
方法,逆变意味着D::Set(T)
必须是<=>或<=>派生自的类型。否则,如果您对类型为<=>的对象的引用存储在变量类型<=>中,则当您调用<=>时,其中<=>的类型为<=>但不是类型<=>,< =>会得到一个它没想到的类型的对象。
在C#中,有意识地决定在重载属性时不允许更改类型,即使它们只有一个getter / setter对,因为它会有非常不一致的行为( <!> quot;你的意思是,我可以用一个getter改变一个类型,但不能同时改变getter和setter的类型?为什么不呢?!?<!> - Anonymous Alternate Universe Newbie)。
其他提示
您可以重新声明(新),但不能同时重新声明和覆盖(使用相同的名称)。 一种选择是使用受保护的方法来隐藏细节 - 这允许同时进行多态和隐藏:
public class Father
{
public Father SomePropertyName
{
get {
return SomePropertyImpl();
}
}
protected virtual Father SomePropertyImpl()
{
// base-class version
}
}
public class Child : Father
{
public new Child SomePropertyName
{
get
{ // since we know our local SomePropertyImpl actually returns a Child
return (Child)SomePropertyImpl();
}
}
protected override Father SomePropertyImpl()
{
// do something different, might return a Child
// but typed as Father for the return
}
}
不,但您可以在2及以上版本中使用泛型:
public class MyClass<T> where T: Person
{
public virtual T SomePropertyName
{
get
{
return ...;
}
}
}
然后父亲和孩子是同一类的通用版本
您可以为父子创建一个公共接口,并返回该接口的类型。
没有。 C#不支持这个想法(它被称为<!> quot; return type covariance <!> quot;)。 但是你可以这样做:
public class FatherProp
{
}
public class ChildProp: FatherProp
{
}
public class Father
{
public virtual FatherProp SomePropertyName
{
get
{
return new FatherProp();
}
}
}
public class Child : Father
{
public override FatherProp SomePropertyName
{
get
{
// override to return a derived type instead
return new ChildProp();
}
}
}
即。使用基类定义的契约,但返回派生类型。我已经做了一个更详细的例子来使这一点更加清晰 - 返回<!>“这个<!>”;再也不会改变任何事情。
可能(但是很乱)测试返回的对象的实际类型(即<!> quot;如果someObject是ChildProp <!>“;),但最好在它上面调用一个虚拟方法正确的类型。
基类虚方法(在本例中为虚拟属性)不仅具有实现,还定义了一个契约:如果子类符合此契约,则子类可以提供SomePropertyName的不同实现(即SomePropertyName返回一个对象)类型<!>“; FatherProp <!>”;)。返回类型<!>的对象;“ChildProp <!>”;派生自<!>“; FatherProp <!>”;符合这份合同。但你无法在<!>中改变合约; Child <!> - 此合同适用于所有来自<!> quot;父<!>;。
的类如果您退后一步并查看更广泛的设计,C#工具箱中还有其他语言结构,您可能还需要考虑这些结构 - 泛型或接口。
没有。 C#不支持这个想法 (它被称为<!> quot;返回类型 协方差QUOT <!>;)
来自维基百科:
在C#编程语言中, 支持返回类型 协方差和参数 增加了代表们的逆转 在该语言的2.0版本中。 既不是协方差也不是逆变 支持方法覆盖。
你可以重新声明(新),但是你 无法重新声明和覆盖 同一时间(同名)。一 选项是使用受保护的方法 隐藏细节 - 这允许两者 多态性和隐藏在同一个 时间:
最好的解决方案是使用泛型:
public class MyClass<T> where T: Person
{
public virtual T SomePropertyNameA
{
get { return ...; }
}
}//Then the Father and Child are generic versions of the same class
这是我能来的最近的(到目前为止):
public sealed class JustFather : Father<JustFather> {}
public class Father<T> where T : Father<T>
{ public virtual T SomePropertyName
{ get { return (T) this; }
}
}
public class Child : Father<Child>
{ public override Child SomePropertyName
{ get { return this; }
}
}
如果没有JustFather
类,除非是其他派生类型,否则无法实例化Father<T>
。