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

C# 如何使构造函数只能由基类访问?,c#,.net,inheritance,constructor,C#,.net,Inheritance,Constructor,如果我想要一个只能从子类访问的构造函数,我可以在构造函数中使用protected关键字 public abstract class BaseClass { public static BaseClass CreateInstance(DataTable dataTable) { return new Child1(dataTable); } public static BaseClass CreateInstance(DataSet dataSet

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

我的子类应该有一个构造函数,它可以被基类访问,但不能从任何其他类访问

这可能吗

这是我当前的代码。问题是子类有一个公共构造函数

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)
    {
    }
}
问题的答案是“不”


OOP中不存在允许子类构造函数仅对其基类可见的东西…

我认为您有两种选择:

  • 使子构造函数
    内部
    。这意味着可以从同一程序集中的所有类型访问它,但在大多数情况下,这就足够了
  • 使子类嵌套在基类中:

    public abstract class BaseClass
    {
        public static BaseClass CreateInstance(DataTable dataTable)
        {
            return new Child1(dataTable);
        }
    
        private class Child1 : BaseClass
        {
            public Child1(DataTable dataTable)
            {
            }
        }
    }
    
    通过这种方式,
    BaseClass
    可以使用构造函数,但没有其他外部类型可以这样做(甚至不能看到子类)


  • 我想是我自己解决的。在阅读了带有嵌套类的svicks解决方案后,我想
    为什么不使用受保护的嵌套类作为参数?

    外部没有人能够创建Arg实例,我的子类中的公共构造函数只能由能够创建
    Arg
    实例的基类使用

    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)
        {
        }
    }
    
    公共抽象类基类
    {
    受保护类Arg
    {
    公共T值{get;set;}
    公共参数(T值){this.value=value;}
    }
    公共静态基类CreateInstance(DataTable DataTable)
    {
    返回新的Child1(新参数(dataTable));
    }
    公共静态基类CreateInstance(数据集)
    {
    返回新的Child2(新参数(数据集));
    }
    }
    公共类Child1:基类
    {
    public Child1(Arg Arg):此(Arg.Value){}
    private Child1(数据表数据表)
    {
    }
    }
    公共类Child2:基类
    {
    public Child2(Arg Arg):此(Arg.Value){}
    公共儿童2(数据集)
    {
    }
    }
    
    通过让基本构造函数接受
    ref
    参数,并执行类似操作(非线程安全),可以在运行时强制执行所需的行为:


    请注意,派生类构造函数调用不完成工厂方法的准备就无法获取控件,或者不完成工厂方法的清理就无法将控件返回给其调用方。但是,,没有什么可以阻止派生类构造函数将其部分构造的实例传递给外部代码,在将控制权返回到工厂方法之前,外部代码可以在任意时间内对其执行任何操作。

    从派生类的类型初始值设定项传递并注册工厂委托,然后您就可以得到该作业完成:

    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 { });
        }
    }
    
    公共抽象类基类{
    静态只读字典
    m_factories=新字典{};
    公共静态基类CreateInstance(DataTable DataTable){
    变量类型=类型(Child1);
    RuntimeHelpers.RunClassConstructor(type.TypeHandle);
    返回(Child1)m_工厂[类型].DynamicInvoke(数据表);
    }
    公共静态基类CreateInstance(数据集){
    变量类型=类型(Child2);
    RuntimeHelpers.RunClassConstructor(type.TypeHandle);
    返回(Child2)m_工厂[类型].DynamicInvoke(数据集);
    }
    受保护的静态无效添加工厂(Func工厂){
    m_工厂。添加(类型(T),工厂);
    }
    }
    公共类Child1:基类{
    Child1(数据表数据表){
    }
    静态Child1(){
    BaseClass.AddFactory((DataTable dt)=>new Child1(dt));
    }
    }
    公共类Child2:基类{
    Child2(数据集){
    }
    静态Child2(){
    BaseClass.AddFactory((数据集ds)=>newchild2(ds));
    }
    }
    公共静态类TestClass{
    公共静态void TestMethod(){
    var child2=BaseClass.CreateInstance(新数据集{});
    var child1=BaseClass.CreateInstance(新数据表{});
    }
    }
    
    如果所有派生类都直接从基类继承,那么就不用担心注册冲突了——没有人可以从另一个类访问构造函数

    对于
    Func
    TArgs
    ,您可能希望将其声明为变量泛型参数,尽管它不是C的一个特性♯, <代码>元组
    是模拟它的方法之一。有关此主题的更多信息,您可能希望了解:


    我不确定这是否可行,基类了解子类有点违背我对inheritance@DanF你是对的,但是一个知道
    Child1
    Child2
    BaseClassFactory
    类是正常的,嵌套类只在基类内部可见,对吗?不确定这是什么意思。@lcfseth,是的,如果您将它们标记为
    private
    。我认为这正是我们想要的(注意工厂方法返回<代码> BaseClass < /代码>)。这是真的,我也需要来自外部的类。@乔恩-它的选项,但不是多级继承的解决方案……也考虑这种情况。这如何保护<代码>子2< /COD>实例化<代码>子1< /代码>?我以为你想保护自己,即使在你自己的程序集中不被错误的实例化?(否则,内部构造函数的解决方案要简单得多。)实际上,C#是否允许公共构造函数上存在不可访问的类型?