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

时间:2015-03-22 17:38:32

标签: c# scope encapsulation derived-class

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

问题:

  • 无法从
  • 派生出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中存储委托,如何在调用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()");
        }
    }

3 个答案:

答案 0 :(得分: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
    }
}

答案 1 :(得分:0)

我仍然在寻找一种没有反思的方法来做到这一点,所以我会留下这个问题,直到有人能弄清楚。目前,这是一个使用反射的解决方案。

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

答案 2 :(得分:0)

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

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