繁体   English   中英

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

[英]Derived class instantiation in abstract base class in C#

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

困难在于基类无法自己创建子类。 所以我在我的基类中引入了一个类型参数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
    }
}

这种方法的缺点是我不能确保只有基类调用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);
    }
}

但这引入了一个新的对象。

是否有更简单的方法来阻止Derivative继承人访问功能(基类可以访问)?

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

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

通过将ComplexComputation移动到基类的构造函数并使GetChild方法抽象为允许派生类在那里选择正确的构造函数,可以避免附加对象。

但是如何将基础构造函数中的计算值param返回给调用派生构造函数? 可能是使用out参数修饰符。 但是因为在C#5.0中,遗憾的是我们无法在基础构造函数调用之前(或之内)声明变量,我们需要在派生构造函数中获取参数。

public abstract class Base<T> where T : Base<T>
{
    public abstract T GetChild();

    protected Base(T parent, out string param)
    {
        param = ComplexComputation();
    }

    protected Base()
    {
    }
}

// --- somewhere else: ---

public class Derivative : Base<Derivative>
{
    public sealed override Derivative GetChild()
    {
        string param;
        return new Derivative(this, out param);
    }

    public Derivative() { }

    private Derivative(Derivative parent, out string param)
        : base(parent, out param)
    {
        // some configuration
    }
}

在我的情况下,我可以将构造函数中的param留下,而是将其存储在public属性中。

除了讨厌的必要hack之外,这种方法对我来说看起来相对干净,但是当需要多次重载GetChild时它不会“缩放”。

也许在C#6.0中,可以直接在基础构造函数调用中声明param https://msdn.microsoft.com/de-de/magazine/dn683793.aspx

暂无
暂无

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

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