[英]How do I make a constructor only accessible by base class?
如果我想要一個只能從子類訪問的構造函數,我可以在構造函數中使用protected
關鍵字。
現在我想要相反的。
我的子類應該有一個構造函數,可以通過它的基類訪問,但不能從任何其他類訪問。
這甚至可能嗎?
這是我目前的代碼。 問題是子類有一個公共構造函數。
public abstract class BaseClass
{
public static BaseClass CreateInstance(DataTable dataTable)
{
return new Child1(dataTable);
}
public static BaseClass CreateInstance(DataSet dataSet)
{
return new Child2(dataSet);
}
}
public class Child1 : BaseClass
{
public Child1(DataTable dataTable)
{
}
}
public class Child2 : BaseClass
{
public Child2(DataSet dataSet)
{
}
}
我想你有兩個選擇:
internal
。 這意味着它可以從同一個程序集中的所有類型訪問,但在大多數情況下應該足夠了。 使子類嵌套在基類中:
public abstract class BaseClass { public static BaseClass CreateInstance(DataTable dataTable) { return new Child1(dataTable); } private class Child1 : BaseClass { public Child1(DataTable dataTable) { } } }
這樣, BaseClass
可以使用構造函數,但沒有其他外部類型可以這樣做(甚至可以看到子類)。
我想我自己就解決了。 在閱讀了帶有嵌套類的svicks解決方案之后,我想why not use an protected nested class as an argument?
來自外部的任何人都無法創建Arg實例,並且我的子類中的公共構造函數只能由可以創建Arg<T>
實例的BaseClass使用。
public abstract class BaseClass
{
protected class Arg<T>
{
public T Value { get; set; }
public Arg(T value) { this.Value = value; }
}
public static BaseClass CreateInstance(DataTable dataTable)
{
return new Child1(new Arg<DataTable>(dataTable));
}
public static BaseClass CreateInstance(DataSet dataSet)
{
return new Child2(new Arg<DataSet>(dataSet));
}
}
public class Child1 : BaseClass
{
public Child1(Arg<DataTable> arg) : this(arg.Value) { }
private Child1(DataTable dataTable)
{
}
}
public class Child2 : BaseClass
{
public Child2(Arg<DataSet> arg) : this(arg.Value) { }
public Child2(DataSet dataSet)
{
}
}
回答問題是“不”
OOP中不存在允許子類構造函數僅對其基類可見的東西......
通過讓基礎構造函數接受ref
參數,可以在運行時強制執行所需的行為,並執行類似(而不是線程安全)的操作:
private int myMagicCounter;
public DerivedClass makeDerived(whatever) // A factory method
{
DerivedClass newThing;
try
{
... do whatever preparation
newThing = new DerivedClass(ref myMagicCounter, whatever);
}
finally
{
... do whatever cleanup
}
return newThing;
}
BaseClass(ref int magicCounter, whatever...)
{
if (magicCounter != myMagicCounter)
throw new InvalidOperationException();
myMagicCounter++;
if (magicCounter != myMagicCounter)
throw new InvalidOperationException();
}
請注意,派生類構造函數調用不可能在沒有完成工廠方法的准備的情況下獲得控制,或者在不進行工廠方法清理的情況下將控制權返回給調用者。 但是,沒有什么可以阻止派生類構造函數將其部分構造的實例傳遞給外部代碼,外部代碼可以在將控制返回到工廠方法之前的任意時間內執行它所喜歡的任何操作。
從派生類的類型初始化程序傳遞並注冊工廠委托,然后您只需完成工作:
public abstract class BaseClass {
static readonly Dictionary<Type, Delegate>
m_factories = new Dictionary<Type, Delegate> { };
public static BaseClass CreateInstance(DataTable dataTable) {
var type = typeof(Child1);
RuntimeHelpers.RunClassConstructor(type.TypeHandle);
return (Child1)m_factories[type].DynamicInvoke(dataTable);
}
public static BaseClass CreateInstance(DataSet dataSet) {
var type = typeof(Child2);
RuntimeHelpers.RunClassConstructor(type.TypeHandle);
return (Child2)m_factories[type].DynamicInvoke(dataSet);
}
protected static void AddFactory<TArgs, T>(Func<TArgs, T> factory) {
m_factories.Add(typeof(T), factory);
}
}
public class Child1:BaseClass {
Child1(DataTable dataTable) {
}
static Child1() {
BaseClass.AddFactory((DataTable dt) => new Child1(dt));
}
}
public class Child2:BaseClass {
Child2(DataSet dataSet) {
}
static Child2() {
BaseClass.AddFactory((DataSet ds) => new Child2(ds));
}
}
public static class TestClass {
public static void TestMethod() {
var child2 = BaseClass.CreateInstance(new DataSet { });
var child1 = BaseClass.CreateInstance(new DataTable { });
}
}
如果所有派生類直接從基類繼承,那么您不必擔心注冊的沖突 - 沒有主體可以從另一個類訪問構造函數。
對於TArgs
的Func<TArgs, T>
你可能要宣布它像可變參數通用參數,雖然它只是不C♯的一個特征, Tuple
是模擬它的方法之一。 有關此主題的更多信息,您可能需要查看:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.