简体   繁体   English

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

[英]How to override method with derived return type in C#?

I want to override a virtual method with a derived class type. 我想用派生类类型重写虚拟方法。 What's the current best way to do this? 目前最好的方法是什么? So far I've found two approaches: 到目前为止,我发现了两种方法:

  1. Use an abstract base class for each derived type; 对每个派生类型使用abstractclass bridge with protected methods. protected方法的桥梁。
  2. Use a protected implementation with a public accessor. public访问器一起使用protected实现。

Base case (no solution implemented, Clone always returns base type A1 ): 基本案例(未实现解决方案, 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
    }

Solution #1 (using abstract base classes for each derived type with protected bridges): 解决方案#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
    }

Solution #2 (using protected implementation with public accessors): 解决方案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); }
    }

So far as I can tell, Solution #1 is the most rigorous approach, but it requires an abstract base class for each derived class which wants to replace the base class 's return type. 据我所知,解决方案#1是最严格的方法,但是它需要每个派生classabstractclass ,该派生class要替换基class的返回类型。

Solution #2's simpler and easier to understand, but it has a small break in internal type safety. 解决方案2更简单易懂,但内部类型安全性方面的漏洞很小。 Specifically, each derived type's public accessor trusts that its protected method will return the correct type. 具体来说,每个派生类型的public访问器都相信其protected方法将返回正确的类型。 So it's possible to have an internal type disconnect, eg: 因此,可能有一个内部类型断开连接,例如:

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

Is there a correct (generally accepted) best practice for overriding methods with derived types? 是否有正确的(通常被接受的)最佳实践覆盖具有派生类型的方法?

You could make the base class generic: 您可以使基类通用:

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() { ... }
}

However this makes me wonder how useful having a common base class is. 但是,这使我想知道拥有一个通用基类有多么有用。 Perhaps the Clone implementations of Derived1 and Derived2 don't need to be part of a common interface. 也许Derived1和Derived2的Clone实现不需要成为公共接口的一部分。

The new keyword implicitly 'overrides' the base functionality anyway. 无论如何, new关键字隐式地“覆盖”基本功能。 Unless for some reason you specifically want override to appear in code, then a single new modifier will suffice. 除非出于某种原因,除非您明确希望override在代码中出现,否则只有一个new修饰符就足够了。 I would also explore abstrating the clone functionality into an interface, it allows you to make more assumptions in code, at a later date. 我还将探讨将克隆功能抽象到一个接口中,它允许您稍后在代码中进行更多假设。

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

EDIT: The resultant possible behaviour: 编辑:结果可能的行为:

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

I'd advise against all of this. 我不建议所有这些。 Just stick to the standard interfaces and patterns for such things. 只需遵循此类标准接口和模式即可。 Implement System.ICloneable... 实施System.ICloneable ...

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

Object Clone()

Simple no? 简单不?

If you must deviate, I would use generics as Andrew Kennan has suggested. 如果您必须偏离,我会按照安德鲁·肯南(Andrew Kennan)的建议使用泛型。 However I would still implement System.ICloneable as it makes the class more inter-operable with other frameworks. 但是,我仍将实现System.ICloneable,因为它使该类与其他框架更可互操作。

In addition ICloneable should be implemented using a protected constructor eg 另外,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
    }
}

This way you can inherit A1 as such... 这样,您可以像这样继承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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM