如何在C#中使用派生返回类型覆盖方法?

时间:2014-03-10 22:54:44

标签: c# inheritance methods override derived-types

我想用派生类类型覆盖虚方法。目前最好的方法是什么?到目前为止,我发现了两种方法:

  1. 为每种派生类型使用abstractclass;用protected方法搭建桥梁。
  2. protected访问者使用public实施。
  3. 基本情况(未实施解决方案,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(对abstract个桥梁使用每个派生类型使用protected基类:

        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(对protected访问者使用public实施):

        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是最严格的方法,但它需要abstract个基础class,每个派生class想要替换基础class 1}}的返回类型。

    解决方案#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); }
        }
    

    是否有一个正确的(普遍接受的)最佳实践来覆盖派生类型的方法?

3 个答案:

答案 0 :(得分:2)

您可以使基类通用:

public abstract class Base<TDerived> where TDerived : Base {
  public abstract TDerived Clone();
}

public class Derived1 : Base<Derived1> {
  public override Derived1 Clone() { ... }
}

public class Derived2 : Base<Derived2> {
  public override Derived2 Clone() { ... }
}

然而,这让我想知道有一个共同的基类是多么有用。也许Derived1和Derived2的Clone实现不需要是通用接口的一部分。

答案 1 :(得分:1)

new关键字无论如何隐式“覆盖”基本功能。除非出于某种原因您特别希望override出现在代码中,否则单个new修饰符就足够了。我还将探索将克隆功能抽象到接口中,它允许您在以后的代码中做出更多假设。

public interface ICloneable<out T>
{
    T Clone();
}

public class A1 : ICloneable<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, ICloneable<A2>
{
    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<A3>
{
    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<A4>
{
    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<A4>)this).Clone();
    }

    A4 ICloneable<A4>.Clone()
    {
        return new A4(X1, X2, X3, X4);
    }
}

答案 2 :(得分:0)

我建议反对所有这些。坚持这些事情的标准接口和模式。实施System.ICloneable ......

http://msdn.microsoft.com/en-us/library/system.icloneable(v=vs.110).aspx

Object Clone()

简单没有?

如果你必须偏离,我会像Andrew Kennan建议的那样使用泛型。但是我仍然会实现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
    }
}

这样你可以继承A1 ......

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
    }
}