如何从封装在管理器 class 中的基 class 派生 classes?

How can I derive classes from a base class that is encapsulated in a manager class?

我有一个管理 class 派生自抽象 BaseClass 的类的 ManagerClass。我需要它以便只有 ManageClass 可以访问 BaseClass 上的某些方法。我还需要某些方法可以在 ManagerClass 的范围之外访问。由于 C# 没有朋友,我将 BaseClass 封装在 ManagerClass 中。

问题:

我怎样才能使这个工作?

    public class ManagerClass
    {
        // This is a singleton class.
        static ManagerClass instance;

        public static T CreateBaseClass<T>() where T : BaseClass, new()
        {
            // Create and return a BaseClass.
            // Everything in BaseClass should be accessible here.
        }

        abstract class BaseClass()
        {
            public bool IsRunning { get; set; }

            virtual void DoStuff()
            {
                // Do stuff.
            }

            abstract void DoOtherStuff();
        }
    }

    public class DerivedClass : ManagerClass.BaseClass
    {
        public override void DoStuff()
        {
            // Do stuff.
        }

        public override void DoOtherStuff()
        {
            // Do other stuff.
        }
    }

    class TestClass
    {
        static void Main(string[] args)
        {
            // Assume singleton is already created here.
            BaseClass bc = ManagerClass.CreateBaseClass<DerivedClass>();
            // bc.IsRunning should be accessible
            // bc.DoStuff() and DoOtherStuff() should not be accessible
        }
    }

**

更新

**

好的,所以在发现无法使用泛型让委托为抽象 class 工作后,我尝试使用工厂接口。这也不起作用,因为我被迫要么创建整个 BaseClass public,要么无法从 ManagerClass 调用 DoStuff() 和 DoOtherStuff()。然后我意识到我根本不需要工厂,因为 DerivedClass 调用 BaseClass 构造函数,我可以在那里做我所有的事情......有点。

所以目前我有一个包装器 class,其中包含一个 BaseClass 和一个范围 class,我可以使用它来存储只有 ManagerClass 应该可以访问的委托或其他成员。 public 成员仍然可以 public 访问,但是 ManagerClass 现在必须通过包装器才能访问这些方法。

新问题

现在唯一的问题是我要为每个 BaseClass 实例存储一个包装器。由于我只需要在我的 BaseClassScope 中存储委托,当调用 BaseClass 静态构造函数时如何存储委托,然后如何使用该委托调用最重写的方法?

    using System;
    using System.Collections.Generic;

    class Program
    {
        static void Main(string[] args)
        {
            ManagerClass.BaseClass[] dc = new DerivedClass[4];

            for (int i = 0; i < 4; i++)
            {
                dc[i] = new DerivedClass();

                // Is accessible from outside ManagerClass
                dc[i].IsRunning = true;

                // Is not accessible from outside ManagerClass
                // dc[i].DoStuff();
            }

            ManagerClass.TestManager();

            // Wait for input.
            Console.ReadKey(true);
        }
    }

    class ManagerClass
    {
        static List<BaseClassWrapper> managedList = new List<BaseClassWrapper>();

        public static void TestManager()
        {
            for (int i = 0; i < managedList.Count; i++)
            {
                // Is accessible from inside ManagerClass
                managedList[i].bcs.DoStuff();
                managedList[i].bcs.DoOtherStuff();
            }
        }

        class BaseClassScope
        {
            public Action DoStuff;
            public Action DoOtherStuff;

            public BaseClassScope(Action ds, Action dos)
            {
                DoStuff = ds;
                DoOtherStuff = dos;
            }
        }

        class BaseClassWrapper
        {
            public BaseClass bc;
            public BaseClassScope bcs;

            public BaseClassWrapper(BaseClass bc, BaseClassScope bcs)
            {
                this.bc = bc;
                this.bcs = bcs;
            }
        }

        public abstract class BaseClass
        {
            public BaseClass()
            {
                Console.WriteLine("BaseClass()");
                var bcs = new BaseClassScope(DoStuff, DoOtherStuff);
                var bcw = new BaseClassWrapper(this, bcs);
                managedList.Add(bcw);
            }

            public bool IsRunning { get; set; }

            protected virtual void DoStuff()
            {
                Console.WriteLine("BaseClass.DoStuff()");
            }

            protected abstract void DoOtherStuff();
        }
    }

    class DerivedClass : ManagerClass.BaseClass
    {
        public DerivedClass()
        {
            Console.WriteLine("DerivedClass()");
        }

        protected override void DoStuff()
        {
            Console.WriteLine("DerivedClass.DoStuff()");
        }

        protected override void DoOtherStuff()
        {
            Console.WriteLine("DerivedClass.DoOtherStuff()");
        }
    }

所以我认为这样的方法可行。我写的时候有点复杂,其中一些可能可以清理,但基本上取决于嵌入式 class 访问父级私有静态变量的能力。我还没有机会测试它,但我认为这应该能达到你想要的效果:

public class ManagerClass
{
    // This is a singleton class.
    static ManagerClass instance;
    private static Func<BaseClassFunctionHolder, BaseClass> _createBaseClass;

    public static T CreateBaseClass<T>() where T : BaseClass, new()
    {
        // Create and return a BaseClass.
        // Everything in BaseClass should be accessible here.

        //example
        BaseClassFunctionHolder holder = new BaseClassFunctionHolder();
        T baseClass = _createBaseClass(holder);

        //access to baseClass methods through holder.DoStuff, and holder.DoOtherStuff
        return baseClass;
    }

    private class BaseClassFunctionHolder
    {
        public Action DoStuff { get; set; }
        public Action DoOtherStuff { get; set; }
    }

    abstract class BaseClass
    {
        static BaseClass()
        {
            _createBaseClass = (holder) => new BaseClass(holder);
        }

        private BaseClass(BaseClassFunctionHolder holder)
        {
            holder.DoStuff = DoStuff;
            holder.DoOtherStuff = DoOtherStuff;
        }

        public bool IsRunning { get; set; }

        virtual void DoStuff()
        {
            // Do stuff.
        }

        abstract void DoOtherStuff();
    }
}

public class DerivedClass : ManagerClass.BaseClass
{
    override void DoStuff()
    {
        // Do stuff.
    }

    override void DoOtherStuff()
    {
        // Do other stuff.
    }
}

class TestClass
{
    static void Main(string[] args)
    {
        // Assume singleton is already created here.
        BaseClass bc = ManagerClass.CreateBaseClass<DerivedClass>();
        // bc.IsRunning should be accessible
        // bc.DoStuff() and DoOtherStuff() should not be accessible
    }
}

我仍在寻找一种无需反思的方法,因此在有人解决之前,我将不回答这个问题。现在,这是一个使用反射的解决方案。

    using System;
    using System.Collections.Generic;
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            ManagerClass.BaseClass dc = new DerivedClass();
            ManagerClass.BaseClass adc = new AnotherDerivedClass();

            // Is accessible from outside ManagerClass
            dc.IsRunning = true;

            // Is not accessible from outside ManagerClass
            // dc.DoStuff();

            ManagerClass.TestManager();

            // Wait for input.
            Console.ReadKey(true);
        }
    }

    class ManagerClass
    {
        static ManagerClass instance;
        static List<BaseClass> managedList = new List<BaseClass>();
        static MethodInfo doStuffMethod = typeof(BaseClass).GetMethod("DoStuff", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.ExactBinding);
        static MethodInfo doOtherStuffMethod = typeof(BaseClass).GetMethod("DoOtherStuff", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.ExactBinding);

        public static ManagerClass Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new ManagerClass();
                }

                return instance;
            }
        }

        public static void TestManager()
        {
            for (int i = 0; i < managedList.Count; i++)
            {
                // DoStuff() and DoOtherStuff need to be accessible only from the ManagerClass.
                // Invocation of the virtual methods calls the derived methods.
                doStuffMethod.Invoke(managedList[i], null);
                doOtherStuffMethod.Invoke(managedList[i], null);
            }
        }

        public abstract class BaseClass
        {
            public BaseClass()
            {
                Console.WriteLine("BaseClass()");
                managedList.Add(this);

                // All of ManagerClass fields are accessible from here:
                // instance, managedList, etc.
            }

            public bool IsRunning { get; set; }

            protected virtual void DoStuff()
            {
                Console.WriteLine("BaseClass.DoStuff()");
            }

            protected abstract void DoOtherStuff();
        }
    }

    class DerivedClass : ManagerClass.BaseClass
    {
        public DerivedClass()
        {
            Console.WriteLine("DerivedClass()");

            // None of the ManagerClass fields are accessible from classes deriving from BaseClass:
            // instance, managedList, etc.
        }

        protected override void DoStuff()
        {
            Console.WriteLine("DerivedClass.DoStuff()");
        }

        protected override void DoOtherStuff()
        {
            Console.WriteLine("DerivedClass.DoOtherStuff()");
        }
    }

    class AnotherDerivedClass : ManagerClass.BaseClass
    {
        public AnotherDerivedClass()
        {
            Console.WriteLine("AnotherDerivedClass()");
        }

        protected override void DoStuff()
        {
            Console.WriteLine("AnotherDerivedClass.DoStuff()");
        }

        protected override void DoOtherStuff()
        {
            Console.WriteLine("AnotherDerivedClass.DoOtherStuff()");
        }
    }

我认为这将是我采用的解决方案。它使用奇怪的重复模板模式,但它消除了所有这些包装器的需要 类,并且它不使用任何反射。

    using System;
    using System.Collections.Generic;

    namespace testapp2
    {
        class Program
        {
            static void Main()
            {
                ClassA a = ClassA.Instance;
                ClassB b = ClassB.Instance;

                ManagerClass.TestManager();

                Console.ReadKey(true);
            }
        }
    }

    class ManagerClass
    {
        static ManagerClass instance;
        static Dictionary<Type, ManagedClass> managedList = new Dictionary<Type, ManagedClass>();

        public ManagerClass Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new ManagerClass();
                }

                return instance;
            }
        }

        ManagerClass()
        {

        }

        public static void TestManager()
        {
            foreach (var kvp in managedList)
            {
                kvp.Value.doStuffCallback();
                kvp.Value.doOtherStuffCallback();
            }
        }

        public static void CreateManagedClass(Type type, Action doStuffCallback, Action doOtherStuffCallback)
        {
            managedList.Add(type, new ManagedClass(doStuffCallback, doOtherStuffCallback));
        }

        public static void DestroyManagedClass(Type type)
        {
            managedList.Remove(type);
        }

        class ManagedClass
        {
            public Action doStuffCallback;
            public Action doOtherStuffCallback;

            public ManagedClass(Action doStuffCallback, Action doOtherStuffCallback)
            {
                this.doStuffCallback = doStuffCallback;
                this.doOtherStuffCallback = doOtherStuffCallback;
            }
        }

        public abstract class ManagedClassBase<T> where T : class, new()
        {
            static T instance;

            public static T Instance
            {
                get
                {
                    if (instance == null)
                    {
                        instance = new T();
                    }

                    return instance;
                }
            }

            protected ManagedClassBase()
            {
                CreateManagedClass(typeof(T), DoStuff, DoOtherStuff);
            }

            ~ManagedClassBase()
            {
                instance = null;
            }

            protected abstract void DoStuff();
            protected abstract void DoOtherStuff();
        }
    }

    class ClassA : ManagerClass.ManagedClassBase<ClassA>
    {
        protected override void DoStuff()
        {
            Console.WriteLine("ClassA.DoStuff()");
        }

        protected override void DoOtherStuff()
        {
            Console.WriteLine("ClassA.DoOtherStuff()");
        }
    }

    class ClassB : ManagerClass.ManagedClassBase<ClassB>
    {
        protected override void DoStuff()
        {
            Console.WriteLine("ClassB.DoStuff()");
        }

        protected override void DoOtherStuff()
        {
            Console.WriteLine("ClassB.DoOtherStuff()");
        }
    }