我怎样才能派生的类从被封装在一个管理器类的基类?(How can I derive classes

2019-10-22 08:33发布

我有一个管理,从一个抽象的BaseClass派生的类一个ManagerClass。 我需要它,以便只有ManageClass可以在BaseClass的访问某些方法。 我还需要某些方法是ManagerClass的范围之外访问。 因为C#没有朋友,我封装ManagerClass内的BaseClass。

问题:

  • BaseClass的是无法访问的,从获得
  • 制作BaseClass的公众,意味着允许DoStuff()和DoOtherStuff()从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
        }
    }

**

更新

**

好了,所以查不到有没有办法让使用泛型抽象类委托工作之后,我尝试使用接口与一个工厂。 这没有任何工作,因为我被迫要么使整个BaseClass的市民,或无法从ManagerClass调用DoStuff()和DoOtherStuff()。 然后我意识到我并不需要一个工厂可言,因为DerivedClass调用BaseClass的构造函数,我可以做我所有的东西在里面......之类的。

因此,在现阶段,我有一个包含BaseClass的,我也可以用它来存储委托或其他成员只有ManagerClass应该有访问范围类的包装类。 公众成员仍然可以公开访问,但现在ManagerClass要经过包装访问方法。

新问题

现在唯一的问题是,我存储的BaseClass的每个实例的包装。 因为我只需要存储在我的BaseClassScope代表,我怎么能当存储基类的静态构造函数被调用的委托,然后我怎么能叫使用该委托的最覆盖方法?

    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()");
        }
    }

Answer 1:

所以我觉得这样的事情可以工作。 它有一个有点令人费解,因为我写的,其中一些可能能够被清理,但基本上取决于嵌入式类来访问父的私有静态变量的能力。 我还没有机会测试它,但我认为这应该达到你想要什么:

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
    }
}


Answer 2:

我仍然在寻找一种方式来做到这一点没有反思,所以我会离开这个问题的答复,直到有人可以计算出来。 现在,这里是一个使用反射的解决方案。

    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()");
        }
    }


Answer 3:

我认为这将是解决我一起去。 它采用了奇异递归模板模式,但它会删除所有的包装类的需求,它不使用任何反映。

    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()");
        }
    }


文章来源: How can I derive classes from a base class that is encapsulated in a manager class?