[英]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.