是否可以在没有强制转换的情况下在C#中实现"虚拟构造函数"模式?

Bil*_*eal 10 c# clone covariance contravariance

我正在编写一个编写C#的程序,最终编译成一个应用程序.我希望每个生成的类型都提供一个"深度克隆"功能,它复制整个数据树.也就是说,我希望有人能够做到:

var x = new Base(); // Base has public virtual Base DeepClone() { ... }
var y = new Derived(); // Derived overrides DeepClone
Base a = x.DeepClone();
Base b = y.DeepClone();
// Derived c = x.DeepClone(); // Should not compile
Derived d = y.DeepClone(); // Does not compile, DeepClone returns Base
Run Code Online (Sandbox Code Playgroud)

代替

var x = new Base();
var y = new Derived();
Base a = x.DeepClone();
Base b = y.DeepClone();
// Derived c = x.DeepClone(); // Should not compile
Derived d = (Derived)y.DeepClone();
Run Code Online (Sandbox Code Playgroud)

但是,C#不允许您在简单的覆盖中执行此操作; 覆盖必须返回与基础上声明的类型相同的类型.

既然我正在编写用于标记样板文件的代码,那么我可以生成一些允许第一个块编译的东西吗?我尝试了类似以下的东西:

abstract class Base
{
    public abstract Base DeepClone();
}

class Base2 : Base
{
    int Member { get; set; }

    public Base2() { /* empty on purpose */ }
    public Base2(Base2 other)
    {
        this.Member = other.Member;
    }

    public override Base2 DeepClone()
    {
        return new Base2(this);
    }
}

sealed class Derived : Base2
{
    string Member2 { get; set; }

    public Derived() { /* empty on purpose */ }
    public Derived(Derived other)
        : base(other)
    {
        this.Member2 = other.Member2;
    }

    public override Derived DeepClone()
    {
        return new Derived(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

但这不会编译,因为覆盖不匹配.我也尝试从基础覆盖该方法并使用"new"关键字隐藏它,但这也不起作用.

Sco*_*ain 4

是的,这是可行的,但是您必须将抽象方法从公共转移到受保护,然后创建一个仅调用受保护方法的公共非抽象函数。派生类只需要实现受保护的函数,并且可以隐藏公共函数,执行本来由客户端执行的转换。

abstract class Base
{
    public Base DeepClone()
    {
        return CloneInternal();
    }

    protected abstract Base CloneInternal();
}

class Base2 : Base
{
    int Member { get; set; }

    public Base2() { /* empty on purpose */ }
    public Base2(Base2 other)
    {
        this.Member = other.Member;
    }

    new public Base2 DeepClone()
    {
        return (Base2)CloneInternal();
    }

    protected override Base CloneInternal()
    {
        return new Base2(this);
    }
}

sealed class Derived : Base2
{
    string Member2 { get; set; }

    public Derived() { /* empty on purpose */ }
    public Derived(Derived other)
        : base(other)
    {
        this.Member2 = other.Member2;
    }

    new public Derived DeepClone()
    {
        return (Derived)CloneInternal();
    }

    protected override Base CloneInternal()
    {
        return new Derived(this);
    }
}
Run Code Online (Sandbox Code Playgroud)