简体   繁体   English

抽象基类强制每个派生类为Singleton

[英]Abstract base class to force each derived classes to be Singleton

How do I make an abstract class that shall force each derived classes to be Singleton ? 如何创建一个抽象类来强制每个派生类为Singleton? I use C#. 我用C#。

that would not work because the singleton needs somwhere a static access and that can not be forced. 这是行不通的,因为单身人士需要一个静态访问,而不能被强制。

for singletonimplemention + examples see: Implementing the Singleton Pattern in C# for singletonimplemention + examples请参阅: 在C#中实现Singleton模式

When you want to enfore compile time checking, this is not possible. 如果要编译时间检查,则无法进行此操作。 With runtime checking you can do this. 通过运行时检查,您可以执行此操作 It's not pretty, but it's possible. 它不漂亮,但它是可能的。 Here's an example: 这是一个例子:

public abstract class Singleton
{
    private static readonly object locker = new object();
    private static HashSet<object> registeredTypes = new HashSet<object>();

    protected Singleton()
    {
        lock (locker)
        {
            if (registeredTypes.Contains(this.GetType()))
            {
                throw new InvalidOperationException(
                    "Only one instance can ever  be registered.");
            }
            registeredTypes.Add(this.GetType());
        }
    }
}

public class Repository : Singleton
{
    public static readonly Repository Instance = new Repository();

    private Repository()
    {
    }
}

Here's an (ugly) way to do this. 这是一种(丑陋的)方式。 It could probably be simplified and improved, but it's my first go at it. 它可能会被简化和改进,但这是我第一次采用它。

The idea is to first make the base class a generic abstract class (as mentioned in comments above), but the type parameter is constrained to derive from the base class itself. 我们的想法是首先使基类成为通用抽象类(如上面的注释中所述),但类型参数被约束为从基类本身派生。 This allows the base class to handle the singleton instance of the derived type. 这允许基类处理派生类型的单例实例。 Note all derived classes should be sealed, as with any singleton class. 请注意,所有派生类都应该密封,就像任何单例类一样。

Next, a protected constructor is allowed, but is required to accept an instance of a special class, SingletonKey, which is a modified singleton. 接下来,允许使用受保护的构造函数,但是需要接受特殊类SingletonKey的实例,SingletonKey是一个修改过的单例。 Derived classes have access to the SingletonKey class definition, but the base class retains private control over the only allowed instance, and thus over construction of all derived objects. 派生类可以访问SingletonKey类定义,但基类保留对唯一允许的实例的私有控制,从而保留对所有派生对象的构造。

Third, the base class will need to be able to call the constructor of the derived class, but this is slightly tricky. 第三,基类需要能够调用派生类的构造函数,但这有点棘手。 The compiler will complain if you try to call the derived keyed constructor, since it isn't guaranteed to exist. 如果您尝试调用派生的键控构造函数,编译器将会抱怨,因为它不能保证存在。 The solution is to add a static delegate that the derived class must initialize. 解决方案是添加派生类必须初始化的静态委托。 So any derived classes will need to provide a simple initialization method. 因此任何派生类都需要提供一个简单的初始化方法。 This initialization method should be called explicitly before attempting to access the instance for the first time in code, or a runtime error will result. 在尝试首次在代码中访问实例之前,应该显式调用此初始化方法,否则将导致运行时错误。

public abstract class Singleton<T> where T : Singleton<T>
{
    protected Singleton(SingletonKey key) { }
    private static SingletonKey _key;
    private static SingletonKey Key
    {
        get
        {
            if (_key == null) SingletonKey.Initialize();
            return _key;
        }
    }
    protected class SingletonKey
    {
        private SingletonKey()
        {
        }
        public static void Initialize()
        {
            if (_key == null)
            {
                _key = new SingletonKey();
            }
        }
    }

    protected static Func<SingletonKey, T> Creator;
    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null) instance = Creator(Key);
            return instance;
        }
    }
}

public class MySingleton : Singleton<MySingleton>
{
    public string Name { get; set; }
    public static void Initialize()
    {
        Creator = (key) => new MySingleton(key);
    }
    protected MySingleton(SingletonKey key) : base(key)
    {
    }
}

Singleton means having private constructors. Singleton意味着拥有私有构造函数。 But you know private members cannot be inherited. 但是你知道私人成员不能被继承。 In C++ there were templates, so you could create a singleton from a template class. 在C ++中有模板,因此您可以从模板类创建单例。 in C#, there aren't templates, so you have to write your own private constructors for every singleton you want. 在C#中,没有模板,所以你必须为你想要的每个单独编写自己的私有构造函数。

Classes in java or C# are not "first-class". java或C#中的类不是“第一类”。 The static part of a class can not be inherited or overridden by subclasses. 子类的静态部分不能由子类继承或覆盖。 See this answer for more details. 有关详细信息,请参阅此答案 Plus, you don't have a concept of meta-class. 另外,你没有元类的概念。

In languages like Smalltalk or Ruby, you can define a new metaclass Singleton which defines a method getInstance . 在Smalltalk或Ruby等语言中,您可以定义一个新的元类Singleton ,它定义了一个方法getInstance Then you can define ClassA and ClassB be instances of the Singleton metaclass. 然后,您可以将ClassAClassB定义为Singleton元类的实例。 Then both classes automatically expose a method getInstance which can be used to create instances objectA or objectB . 然后,这两个类自动公开一个方法getInstance ,该方法可用于创建实例objectAobjectB Isn't that cool? 那不是很酷吗? Well, in practice you don't use metaclass frequently, and the singleton is actually the only usage of them that makes sense and that I'm aware of. 好吧,在实践中你不经常使用元类,而单例实际上是它们的唯一用法,它是有意义的并且我知道。

I believe I tried to achieve something similar ie enforce a common interface and the singleton pattern on a group of classes. 我相信我试图实现类似的东西,即在一组类上强制执行通用接口和单例模式。 This was my solution: 这是我的解决方案:

// Common interface of my singleton classes
public interface IMySingletonClass
{
    string ValueGetter();

    void ValueSetter(string value);
}

// Generic abstract base class
public abstract class Singleton<T>: IMySingletonClass
{
    private static readonly object instanceLock = new object();
    private static T instance; // Derived class instance

    // Protected constructor accessible from derived class
    protected Singleton()
    {
    }

    // Returns the singleton instance of the derived class
    public static T GetInstance()
    {
        lock (instanceLock)
        {
            if (instance == null)
            {
                instance = (T)Activator.CreateInstance(typeof(T), true);
            }
            return instance;
        }
    }

    // IMySingletonClass interface methods
    public abstract string ValueGetter();

    public abstract void ValueSetter(string value);
}

// Actual singleton class
public class MySingletonClass : Singleton<MySingletonClass>
{
    private string myString;

    private MySingletonClass()
    {
        myString = "Initial";
    }

    public override string ValueGetter()
    {
        return myString;
    }

    public override void ValueSetter(string value)
    {
        myString = value;
    }
}

Here is a simple test: 这是一个简单的测试:

class Program
{
    static void Main(string[] args)
    {
        MySingletonClass r1 = MySingletonClass.GetInstance();
        Console.WriteLine("R1 value = {0}", r1.ValueGetter());
        r1.ValueSetter("Changed through R1");
        MySingletonClass r2 = MySingletonClass.GetInstance();
        Console.WriteLine("R2 value = {0}", r2.ValueGetter());

        Console.ReadKey();
    }
}

Please note that you can easily remove the common interface from the generic abstract singleton class if you just need the basic "template". 请注意,如果您只需要基本的“模板”,则可以轻松地从通用抽象单例类中删除公共接口。

Here my implementation of Singleton inheritance: 这里是我对Singleton继承的实现:

using System;
using System.Reflection;

namespace Mik.Singleton
{
    class Program
    {
        static void Main()
        {
            //You can not create an instance of class directly
            //Singleton1 singleton1 = new Singleton1();

            Singleton1 singleton1 = Singleton1.Instance;
            Singleton2 singleton2 = Singleton2.Instance;

            Console.WriteLine(singleton1.Singleton1Text);
            Console.WriteLine(singleton2.Singleton2Text);

            Console.ReadLine();
        }
    }

    public class SingletonBase<T> where T : class
    {
        #region Singleton implementation

        private static readonly object lockObj = new object();
        private static T _instance;

        protected SingletonBase() { }

        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (lockObj)
                    {
                        if (_instance == null)
                            _instance = CreateInstance();
                    }
                }
                return _instance;
            }
        }

        private static T CreateInstance()
        {
            ConstructorInfo constructor = typeof(T).GetConstructor(
                            BindingFlags.Instance | BindingFlags.NonPublic,
                            null, new Type[0],
                            new ParameterModifier[0]);

            if (constructor == null)
                throw new Exception(
                    $"Target type is missing private or protected no-args constructor: {typeof(T).FullName}");
            try
            {
                T instance = constructor.Invoke(new object[0]) as T;

                return instance;
            }
            catch (Exception e)
            {
                throw new Exception(
                    "Failed to create target: type=" + typeof(T).FullName, e);
            }
        }

        #endregion Singleton implementation
    }

    public class Singleton1 : SingletonBase<Singleton1>
    {
        private Singleton1() { }

        public string Singleton1Text { get; } = "Singleton1Text value";
    }

    public class Singleton2 : SingletonBase<Singleton2>
    {
        private Singleton2() { }

        public string Singleton2Text { get; } = "Singleton2Text value";
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在非抽象基类的派生类中强制重写? - How to force overrides in a derived class from non abstract base classes? 重写基类抽象方法并将其隐藏在派生类中 - Overriding Base Class abstract methods and hiding them in derived classes Array中抽象类的派生类 - Derived classes of abstract class in an Array 如何使用Singleton将派生类型传递给抽象类 - How to pass derived type to abstract class with singleton 有没有一种方法可以强制派生类实现抽象类或嵌套在基类中的接口? - Is there a way to force a derived class to implement an abstract class or an interface nested in base class? null抽象基类/派生类的合并问题 - null coalescing issue with abstract base/derived classes 在基类构造函数中使用抽象类作为参数,以在派生类中具有更多特定类型 - Using abstract class as parameter in base class constructor to have more specific types in derived classes 基类和2个派生类的继承 - Inheritance of a base class and 2 derived classes 我是否需要序列化抽象基类以使派生类可序列化 - Do I need to serialize the abstract base class to make the derived classes serializable 在抽象基类的静态方法中实例化几个派生类中的任何一个(取决于参数) - Instantiate any one of several derived classes (depending on an argument) within a static method of the abstract base class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM