C#抽象基类中的派生类实例化

omi*_*nug 5 c# inheritance

我的目标是编写一个抽象基类,其中包含派生“子实例”的方法。在这个方法中已经完成了一些计算,这在所有派生类中都很常见。

困难在于基类不能自己创建子类。所以我T在我的基类中引入了一个类型参数和一个protected abstract返回T.

public abstract class Base<T> where T : Base<T>
{
    public T GetChild()
    {
        string param = ComplexComputation();
        return NewInstanceFrom(param);
    }

    protected abstract T NewInstanceFrom(string param);
}

// --- somewhere else: ---

public class Derivative : Base<Derivative>
{
    public Derivative() { }

    protected sealed override Derivative NewInstanceFrom(string param)
    {
        return new Derivative(param);
    }

    private Derivative(string param)
    {
        // some configuration
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是我不能确保NewInstanceFrom它只被基类调用。它也可以由继承自 的类调用Derivative。这就是我想要避免的。

所以我可以将功能封装在一个私有类或委托中:

public abstract class Base<T> where T : Base<T>
{
    public T GetChild()
    {
        string param = ComplexComputation();
        return subElementDerivator(param);
    }

    protected Base<T>(Func<string, T> subElementDerivator)
    {
        this.subElementDerivator = subElementDerivator;
    }

    private Func<string, T> subElementDerivator;
}

// --- somewhere else: ---

public class Derivative : Base<Derivative>
{
    public Derivative()
        : base(deriveSubElement)    
    {
    }

    private Derivative(string param)
        : base(deriveSubElement)
    {
        // some configuration
    }

    private static Derivative deriveSubElement(string param)
    {
        return new Derivative(param);
    }
}
Run Code Online (Sandbox Code Playgroud)

但这引入了一个新对象。

有没有更简单的方法来阻止Derivative.

Meh*_*taş 2

您可以使用显式接口实现来隐藏工厂方法。任何客户端Create在转换后仍然可以调用该方法,但至少智能感知不会帮助开发人员。

public interface ISecretFactory<T>
{
    T Create(string param);
}

public abstract class Base<T> where T : Base<T>, ISecretFactory<T>
{
    public T GetChild()
    {
        // We are sure type T always implements ISecretFactory<T>
        var factory = this as ISecretFactory<T>;
        return factory.Create("base param");
    }
}

public class Derivative : Base<Derivative>, ISecretFactory<Derivative>
{
    public Derivative()
    {

    }

    private Derivative(string param)
    {

    }

    Derivative ISecretFactory<Derivative>.Create(string param)
    {
        return new Derivative(param);
    }
}

public class SecondDerivative : Derivative
{
    public void F()
    {
        // intellisense won't show Create method here.
        // But 'this as ISecretFactory<Derivative>' trick still works.
    }
}
Run Code Online (Sandbox Code Playgroud)