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

Accessing inherited members from static methods - Singleton Inheritance?

问题总结

其实我只是想使用普通的继承功能。
问题是,我的一些方法是静态的,所以它们不能像平常那样访问继承的属性。 此外,我不能将任何东西传递给静态方法(如对象的实例),因为它们被 "external triggers".
调用 另一方面,我不需要多个实例,这意味着像单例这样的东西就可以了。

让我逐步向您解释我的情况:
(或直接跳转到第一个代码示例以查看 MCV 示例)

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

我正在使用库 Harmony 来修补现有程序集的方法。 修补方法必须是静态的,并由库的 "hooks" 调用。
我将新玩家升级添加到游戏中。对于每个我想打补丁的升级,我都会创建一个 class 的成员,比如名称、描述、图片...... 一个升级必须只打一次补丁,所以这里的解决方案是让所有东西都静态化。
但是...

要求 2 - 继承

因为这些升级有很多共同的成员和方法,所以我做了一个 BaseUpgrade class 并从中派生。
每个特定的实现现在都可以将它们的值分配给公共字段,如名称、描述......并继承其余部分(使用成员的方法)。
然而,成员不再可以从静态修补方法访问。为此,我可以使用单例。
我也想继承所有 Singleton 的东西,使其通用。这样只有基础 class 拥有所有的 Singeton 代码。
一种方法是这个解决方案:
然而...

要求 3 - 拥有基础集合 class

我需要有基础集合 class 并在字典中使用它们(作为键和值)。但这似乎不适用于通用 classes.
我找到 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();
        }
    }
}

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

基本上创建一个接口或class "above" 单例class(单例class 继承它)并将其用于集合或方法参数。

在这个新的 non-generic class 中,我放置了所有字段和方法。 topnon-genericclass和泛型class的构造函数是受保护的,所以不能实例化。

工作解决方案

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()

特定子 class 的构造函数需要 public。这意味着不强制执行单身人士,但 "just" 一个选项(请参阅输出示例)。

BTownTKD states that in his answer he states that fact and links to his attempt to solve this via reflection an manually invoking private constructors here: Singleton.cs

结论

感谢为这个问题做了 MCV 示例并再次尝试,大大降低了复杂性,我自己找到了解决方案。
所以这里的提问过程和改进我的初始 post 帮助了我。 :-)