从静态方法访问继承的成员 - Singleton继承?

时间:2018-04-06 13:38:47

标签: c# inheritance static-methods member non-static

问题摘要

实际上我只想使用普通的继承功能 问题是,我的一些方法是静态的,因此它们无法正常访问继承的属性。 此外,我无法将任何内容传递给静态方法(如对象的实例),因为它们被"外部触发器调用"。
另一方面,我不需要多个实例,这意味着单身就好了。

让我一步一步向你解释我的情况:
(或者只是跳转到第一个代码示例以查看MCV示例)

要求1 - 访问成员的静态方法

我使用库Harmony来修补现有程序集的方法。 修补方法必须是静态的,并由"钩子"图书馆 我为游戏添加了新的玩家升级。对于我要修补的每次升级,我创建了一个包含成员的类,如名称,描述,图像...... 一次升级必须只修补一次,因此这里的解决方案是使静态变为静止 但是......

要求2 - 继承

因为这些升级共享了许多常见的成员和方法,所以我创建了一个BaseUpgrade类并从中派生出来。
现在,每个特定的实现都可以将它们的值分配给公共字段,如名称,描述......并继承其余的(使用成员的方法)。
然而,成员无法通过静态修补方法访问。为此,我可以使用单身人士 我想继承所有Singleton的东西,使它成为通用的。这样只有基类具有所有Singeton代码 一种方法是这种解决方案:https://stackoverflow.com/a/16865465
但是......

要求3 - 拥有基类​​的集合

我需要拥有基类的集合并在字典中使用它们(作为键和值)。但这似乎与泛型类无关 我找到了Collection of generic types,但我被卡住了。我不知道合并这个是否真的有效。至少它会使事情变得更复杂。

那会有用吗?对我的问题可能有一个更简单的方法吗?

MCV基本场景示例

using System;
using System.Collections.Generic;

namespace Using_Singleton
{

    // This is the version trying to incorperate the inheritable singleton
    class Base<T> where T : Base<T>, new()
    {
        #region Singleton stuff

        private static T _instance;

        public static T Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new T();
                return _instance;
            }
            set => _instance = value;
        }

        #endregion

        public string name;     // Should be accessible by the derived class' static methods
        public string desc;

        protected Base()
        {
            name = "Base";
        }

        public void printName()
        {
            Console.WriteLine(name);
        }
    }

    class FirstChild : Base<FirstChild>
    {
        public int number;      // Should be accessible by the class' static methods

        public FirstChild()
        {
            name = "The first child";
            number = 7;
        }

        public static void StaticMethod_FirstChild()
        {
            Console.WriteLine("StaticMethod_FirstChild: I can access all member variables! :-)");
            Console.WriteLine("Name: " + Instance.name + ", Number: " + Instance.number);     // This is now working
        }

    }

    class SecondChild : Base<SecondChild>
    {
        public float myfloat;

        public SecondChild()
        {
            name = "The second child";
            myfloat = 0.3f;
        }

        public static void StaticMethod_SecondChild()
        {
            Console.WriteLine("StaticMethod_SecondChild: I can access all member variables! :-)");
            Console.WriteLine("Name 2x: " + Instance.name + " " + Instance.name);       // This is now working
        }
    }

    class Manager       // Manages instances/singletons which derive from "Base" by using a collection of the Base class
    {
        //Dictionary<string, Base> itemDict;        // ******* This is now broken

        public Manager()
        {
            //itemDict = new Dictionary<string, Base>();

            //Base addItem;

            //addItem = new FirstChild();
            //itemDict.Add(addItem.GetType().Name, addItem);

            //addItem = new SecondChild();
            //itemDict.Add(addItem.GetType().Name, addItem);

            // Simulating the external call of one static method
            SecondChild.StaticMethod_SecondChild();
            Console.WriteLine();
        }

        public void DoSomething()
        {
            //foreach (var item in itemDict)
            //{
            //  item.Value.printName();
            //}
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Manager manager = new Manager();
            manager.DoSomething();

            Console.ReadLine();
        }
    }

}

使用可继承单身人士的示例

using System;
using System.Collections.Generic;

namespace Using_Singleton
{

    // This is the version trying to incorperate the inheritable singleton
    class Base<T> where T : Base<T>, new()
    {
        #region Singleton stuff

        private static T _instance;

        public static T Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new T();
                return _instance;
            }
            set => _instance = value;
        }

        #endregion

        public string name;     // Should be accessible by the derived class' static methods
        public string desc;

        protected Base()
        {
            name = "Base";
        }

        public void printName()
        {
            Console.WriteLine(name);
        }
    }

    class FirstChild : Base<FirstChild>
    {
        public int number;      // Should be accessible by the class' static methods

        public FirstChild()
        {
            name = "The first child";
            number = 7;
        }

        public static void StaticMethod_FirstChild()
        {
            Console.WriteLine("StaticMethod_FirstChild: I can access all member variables! :-)");
            Console.WriteLine("Name: " + Instance.name + ", Number: " + Instance.number);     // This is now working
        }

    }

    class SecondChild : Base<SecondChild>
    {
        public float myfloat;

        public SecondChild()
        {
            name = "The second child";
            myfloat = 0.3f;
        }

        public static void StaticMethod_SecondChild()
        {
            Console.WriteLine("StaticMethod_SecondChild: I can access all member variables! :-)");
            Console.WriteLine("Name 2x: " + Instance.name + " " + Instance.name);       // This is now working
        }
    }

    class Manager       // Manages instances/singletons which derive from "Base" by using a collection of the Base class
    {
        //Dictionary<string, Base> itemDict;        // ******* This is now broken

        public Manager()
        {
            //itemDict = new Dictionary<string, Base>();

            //Base addItem;

            //addItem = new FirstChild();
            //itemDict.Add(addItem.GetType().Name, addItem);

            //addItem = new SecondChild();
            //itemDict.Add(addItem.GetType().Name, addItem);

            // Simulating the external call of one static method
            SecondChild.StaticMethod_SecondChild();
            Console.WriteLine();
        }

        public void DoSomething()
        {
            //foreach (var item in itemDict)
            //{
            //  item.Value.printName();
            //}
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Manager manager = new Manager();
            manager.DoSomething();

            Console.ReadLine();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

在向小例子添加可继承单例后,我尝试添加对通用集合的支持,如suggested by Jon Saunders

基本上将接口或类“置于”单例类(单例类继承它)之上,并将其用于集合或方法参数。

在这个新的非泛型类中,我已经放了所有的字段和方法。顶级非泛型类和泛型类的构造函数受到保护,因此无法实例化它们。

工作解决方案

using System;
using System.Collections.Generic;

namespace Using_Singleton_And_GenericCollection
{
    // This is the version trying to incorperate the inheritable singleton and a generic collection

    abstract class NonGenericBase       // Adding this (class or interface) make the use of collections possible.
    {
        public string name;
        public string desc;

        public void printName()
        {
            Console.WriteLine("\t" + name);
        }

        protected NonGenericBase() { }
    }

    class Base<T> : NonGenericBase where T : Base<T>, new()
    {
        #region Singleton stuff

        protected static T _instance;

        public static T Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new T();
                return _instance;
            }
            set => _instance = value;
        }

        #endregion

        //public string name;     // Moved to parent
        //public string desc;

        protected Base()
        {
            name = "Base";
        }
    }


    class FirstChild : Base<FirstChild>
    {
        public int number;      // Should be accessible by the class' static methods

        public FirstChild()
        {
            name = "The first child";
            number = 7;
        }

        public static void StaticMethod_FirstChild()
        {
            Console.WriteLine("\tStaticMethod_FirstChild: I can access all member variables! :-)");
            Console.WriteLine("\tName: " + Instance.name + ", Number: " + Instance.number);     // This is now working
        }
    }

    class SecondChild : Base<SecondChild>
    {
        public float myfloat;

        public SecondChild()
        {
            name = "The second child";
            myfloat = 0.3f;
        }

        public static void StaticMethod_SecondChild()
        {
            Console.WriteLine("\tStaticMethod_SecondChild: I can access all member variables! :-)");
            Console.WriteLine("\tName 2x: " + Instance.name + ", " + Instance.name);       // This is now working
        }
    }


    class Manager       // Manages instances/singletons which derive from "Base" by using a collection of the Base class
    {
        public Dictionary<string, NonGenericBase> itemDict;

        public Manager()
        {
            itemDict = new Dictionary<string, NonGenericBase>();

            NonGenericBase addItem;

            addItem = FirstChild.Instance;
            itemDict.Add(addItem.GetType().Name, addItem);

            addItem = SecondChild.Instance;
            itemDict.Add(addItem.GetType().Name, addItem);
        }

        public void DoSomething()
        {
            foreach (var item in itemDict)
            {
                item.Value.printName();
            }
            Console.WriteLine();
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            var sec = new SecondChild();

            Console.WriteLine("Access Singletons");
            Manager manager = new Manager();
            manager.DoSomething();

            Console.WriteLine("Change Singletons");
            manager.itemDict[nameof(FirstChild)].name = "first name changed";
            SecondChild.Instance.name = "second name changed too";
            manager.DoSomething();

            Console.WriteLine("Create and change a non-Singleton instance of FirstChild");
            var initItem = new FirstChild();
            initItem.printName();
            initItem.name = "Non-Singleton name changed";
            initItem.printName();
            Console.WriteLine();

            Console.WriteLine("Access Singletons");
            manager.DoSomething();

            Console.WriteLine("Call static method of FirstChild");
            FirstChild.StaticMethod_FirstChild();         //Simulating the external call of one static method
            Console.WriteLine();

            Console.ReadKey();
        }
    }
} 

输出

Access Singletons
        The first child
        The second child

Change Singletons
        first name changed
        second name changed too

Create and change a non-Singleton instance of FirstChild
        The first child
        Non-Singleton name changed

Access Singletons
        first name changed
        second name changed too

Call static method of FirstChild
        StaticMethod_FirstChild: I can access all member variables! :-)
        Name: first name changed, Number: 7

买者

因为这里有“new()”

class Base<T> : NonGenericBase where T : Base<T>, new()

特定子类的构造函数需要公开。这意味着单身人士不会被强制执行,而是“只是”一个选项(请参阅输出示例)。

BTownTKD states that in his answer他说明了这个事实以及他试图通过反映手动调用私人构造函数来解决这个问题的链接:Singleton.cs

结论

感谢您为此问题做了MCV示例,并以极低的复杂性再次尝试,我自己找到了解决方案。
所以这里的质疑过程和改进我的初始帖子帮助了我。 : - )