如何使构造函数只能由基类访问?

如果我想要一个只能从子类访问的构造函数,我可以在构造函数中使用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) { } } 

我想你有两个选择:

  1. 使子构造函数internal 。 这意味着它可以从同一个程序集中的所有类型访问,但在大多数情况下应该足够了。
  2. 使子类嵌套在基类中:

     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实例,我的子类中的公共结构只能由BaseClass使用,BaseClass可以创建Arg实例。

 public abstract class BaseClass { protected class Arg { public T Value { get; set; } public Arg(T value) { this.Value = value; } } public static BaseClass CreateInstance(DataTable dataTable) { return new Child1(new Arg(dataTable)); } public static BaseClass CreateInstance(DataSet dataSet) { return new Child2(new Arg(dataSet)); } } public class Child1 : BaseClass { public Child1(Arg arg) : this(arg.Value) { } private Child1(DataTable dataTable) { } } public class Child2 : BaseClass { public Child2(Arg 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 m_factories = new Dictionary { }; 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(Func 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 { }); } } 

如果所有派生类直接从基类inheritance,那么您不必担心注册的冲突 – 没有主体可以从另一个类访问构造函数。

对于Func您可能希望将其声明为可变参数generics参数,尽管它不是C♯的一个特性, Tuple是模拟它的方法之一。 有关此主题的更多信息,您可能需要查看:

在c#中模拟可变参数模板