抽象基类强制每个派生类都是 Singleton

发布于 2024-09-02 14:32:50 字数 45 浏览 2 评论 0原文

如何创建一个抽象类来强制每个派生类都是 Singleton ?我使用 C#。

How do I make an abstract class that shall force each derived classes to be Singleton ? I use C#.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

带刺的爱情 2024-09-09 14:32:50

这是行不通的,因为单例需要在某个地方进行静态访问,并且不能强制这样做。

有关单例实现 + 示例,请参阅:在 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#

本王不退位尔等都是臣 2024-09-09 14:32:50

当您想要进行编译时检查时,这是不可能的。通过运行时检查,您可以做到这一点。这并不漂亮,但这是可能的。这是一个例子:

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

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()
    {
    }
}
一场信仰旅途 2024-09-09 14:32:50

Singleton 意味着拥有私有构造函数。但你知道私有成员不能被继承。 C++ 中有模板,因此您可以从模板类创建单例。在 C# 中,没有模板,因此您必须为每个所需的单例编写自己的私有构造函数。

Singleton means having private constructors. But you know private members cannot be inherited. In C++ there were templates, so you could create a singleton from a template class. in C#, there aren't templates, so you have to write your own private constructors for every singleton you want.

泪冰清 2024-09-09 14:32:50

java 或 C# 中的类不是“一流的”。类的静态部分不能被子类继承或覆盖。有关更多详细信息,请参阅此答案。另外,您没有元类的概念。

在 Smalltalk 或 Ruby 等语言中,您可以定义一个新的元类 Singleton,它定义了一个方法 getInstance。然后,您可以将 ClassAClassB 定义为 Singleton 元类的实例。然后,这两个类都会自动公开一个方法 getInstance,该方法可用于创建实例 objectAobjectB。这不是很酷吗?嗯,在实践中,您不会经常使用元类,而单例实际上是我所知道的唯一有意义的用法。

Classes in java or C# are not "first-class". 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. Then you can define ClassA and ClassB be instances of the Singleton metaclass. Then both classes automatically expose a method getInstance which can be used to create instances objectA or objectB. 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.

寄人书 2024-09-09 14:32:50

这是一种(丑陋的)方法来做到这一点。它可能可以简化和改进,但这是我第一次尝试。

这个想法是首先使基类成为通用抽象类(如上面的注释中提到的),但类型参数被限制为从基类本身派生。这允许基类处理派生类型的单例实例。请注意,所有派生类都应密封,就像任何单例类一样。

接下来,允许使用受保护的构造函数,但需要接受特殊类 SingletonKey 的实例,该类是经过修改的单例。派生类可以访问 SingletonKey 类定义,但基类保留对唯一允许的实例的私有控制,从而保留对所有派生对象的构造的私有控制。

第三,基类需要能够调用派生类的构造函数,但这有点棘手。如果您尝试调用派生键控构造函数,编译器会抱怨,因为不能保证它存在。解决方案是添加派生类必须初始化的静态委托。因此任何派生类都需要提供一个简单的初始化方法。在代码中首次尝试访问实例之前,应显式调用此初始化方法,否则将导致运行时错误。

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

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

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)
    {
    }
}
梦在深巷 2024-09-09 14:32:50

我相信我试图实现类似的目标,即在一组类上强制执行通用接口和单例模式。这是我的解决方案:

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

这是一个简单的测试:

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

请注意,如果您只需要基本的“模板”,您可以轻松地从通用抽象单例类中删除公共接口。

I believe I tried to achieve something similar i.e. 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".

寂寞美少年 2024-09-09 14:32:50

这是我的单例继承的实现:

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

Here my implementation of Singleton inheritance:

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";
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文