簡體   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