如何在C#中使用派生返回类型覆盖方法?
我想用派生类类型覆盖虚方法。 目前最好的方法是什么? 到目前为止,我发现了两种方法:
- 为每个派生类型使用
abstract
基class
; 桥接与protected
方法。 - 使用带有
public
访问器的protected
实现。
基本情况(没有实现解决方案, Clone
总是返回基类型A1
):
public class A1 { public int X1 { get; set; } public A1(int x1) { this.X1 = x1; } public virtual A1 Clone() { return new A1(X1); } } public class A2 : A1 { public int X2 { get; set; } public A2(int x1, int x2) : base(x1) { this.X2 = x2; } public override A1 Clone() { return new A2(X1, X2); } //can't explicitly return A2 } public class A3 : A2 { public int X3 { get; set; } public A3(int x1, int x2, int x3) : base(x1, x2) { this.X3 = x3; } public override A1 Clone() { return new A3(X1, X2, X3); } //can't explicitly return A3 }
解决方案#1(使用带有protected
网桥的每个派生类型的abstract
基类):
public class B1 { public int X1 { get; set; } public B1(int x1) { this.X1 = x1; } public virtual B1 Clone() { return new B1(X1); } } public abstract class B2_Base : B1 { public B2_Base(int x1) : base(x1) { } public sealed override B1 Clone() { return this.CloneAsB1(); } protected abstract B1 CloneAsB1(); } public class B2 : B2_Base { public int X2 { get; set; } public B2(int x1, int x2) : base(x1) { this.X2 = x2; } protected sealed override B1 CloneAsB1() { return this.Clone(); } public new virtual B2 Clone() { return new B2(X1, X2); } //CAN explicitly return B2 } public abstract class B3_Base : B2 { public B3_Base(int x1, int x2) : base(x1, x2) { } public sealed override B2 Clone() { return this.CloneAsB2(); } protected abstract B2 CloneAsB2(); } public class B3 : B3_Base { public int X3 { get; set; } public B3(int x1, int x2, int x3) : base(x1, x2) { this.X3 = x3; } protected sealed override B2 CloneAsB2() { return this.Clone(); } public new virtual B3 Clone() { return new B3(X1, X2, X3); } //CAN explicitly return B3 }
解决方案#2(使用带有public
访问器的protected
实现):
public class C1 { public int X1 { get; set; } public C1(int x1) { this.X1 = x1; } public C1 Clone() { return this.CloneImplementation(); } protected virtual C1 CloneImplementation() { return new C1(X1); } } public class C2 : C1 { public int X2 { get; set; } public C2(int x1, int x2) : base(x1) { this.X2 = x2; } public new C2 Clone() { return this.CloneImplementation() as C2; } //trusts CloneImplementation to return a C2 protected override C1 CloneImplementation() { return new C2(X1, X2); } } public class C3 : C2 { public int X3 { get; set; } public C3(int x1, int x2, int x3) : base(x1, x2) { this.X3 = x3; } public new C3 Clone() { return this.CloneImplementation() as C3; } //trusts CloneImplementation to return a C3 protected override C1 CloneImplementation() { return new C3(X1, X2, X3); } }
据我所知,解决方案#1是最严格的方法,但它需要每个派生class
的abstract
基class
,它想要替换基class
的返回类型。
解决方案#2更简单易懂,但内部类型安全性略有突破。 具体来说,每个派生类型的public
访问者都信任其protected
方法将返回正确的类型。 因此可以使内部类型断开,例如:
public class C2 : C1 { public int X2 { get; set; } public C2(int x1, int x2) : base(x1) { this.X2 = x2; } public new C2 Clone() { return this.CloneImplementation() as C2; } //trusts CloneImplementation to return a C2 protected override C1 CloneImplementation() { return new C1(X1); } }
是否有一个正确的(普遍接受的)最佳实践来覆盖派生类型的方法?
您可以使基类通用:
public abstract class Base where TDerived : Base { public abstract TDerived Clone(); } public class Derived1 : Base { public override Derived1 Clone() { ... } } public class Derived2 : Base { public override Derived2 Clone() { ... } }
然而,这让我想知道有一个共同的基类是多么有用。 也许Derived1和Derived2的Clone实现不需要是通用接口的一部分。
无论如何, new
关键字隐式“覆盖”基本function。 除非由于某种原因你特别希望override
出现在代码中,否则一个new
修饰符就足够了。 我还将探索将克隆function抽象到接口中,它允许您在以后的代码中做出更多假设。
public interface ICloneable { T Clone(); } public class A1 : ICloneable { public int X1 { get; set; } public A1(int x1) { this.X1 = x1; } public virtual A1 Clone() { return new A1(X1); } } public class A2 : A1, ICloneable { public int X2 { get; set; } public A2(int x1, int x2) : base(x1) { this.X2 = x2; } public virtual new A2 Clone() { return new A2(X1, X2); } } public class A3 : A2, ICloneable { public int X3 { get; set; } public A3(int x1, int x2, int x3) : base(x1, x2) { this.X3 = x3; } public virtual new A3 Clone() { return new A3(X1, X2, X3); } }
编辑:由此产生的可能行为:
public class A4 : A3, ICloneable { public int X4 { get; set; } public A4(int x1, int x2, int x3, int x4) : base(x1, x2, x3) { this.X4 = x4; } public override A3 Clone() { return ((ICloneable )this).Clone(); } A4 ICloneable .Clone() { return new A4(X1, X2, X3, X4); } }
我建议反对所有这些。 坚持这些事情的标准接口和模式。 实施System.ICloneable ……
http://msdn.microsoft.com/en-us/library/system.icloneable(v=vs.110).aspx
Object Clone()
简单没有?
如果你必须偏离,我会像Andrew Kennan建议的那样使用generics。 但是我仍然会实现System.ICloneable,因为它使类更容易与其他框架互操作。
另外,ICloneable应该使用受保护的构造函数来实现,例如
public class A1 : ICloneable { public A1(int x1) { this.X1 = x1; } protected A1(A1 copy) { this.X1 = copy.X1; } public int X1 { get; set; } public virtual object Clone() { return new A1(this); // Protected copy constructor } }
这样你可以inheritanceA1 ……
public class B1 : A1, ICloneable { public B1(int x1, int y1) : base(x1) { this.Y1 = y1; } protected B1(B1 copy) : base(copy) { this.Y1 = copy.Y1; } public int Y1 { get; set; } public virtual object Clone() { return new B1(this); // Protected copy constructor } }