.NET的一个明显的单例实现?

时间:2009-06-04 21:38:22

标签: c# .net singleton

我在考虑懒惰单例初始化的经典问题 - 整个问题的低效率:

if (instance == null)
{
    instance = new Foo();
}
return instance;

任何知道Singleton是什么的人都熟悉这个问题(你只需要if一次)。这是微不足道但令人恼火的。

所以,我想到了一个替代解决方案,至少对于.NET来说(尽管它应该可以在任何地方使用) 它有一些等同于函数指针:

public class Foo
{
    private delegate Foo FooReturner();

    private static Foo innerFoo;

    private static FooReturner fooReturnHandler = new FooReturner(InitialFooReturner);

    public static Foo Instance
    {
        get
        {
            return fooReturnHandler();
        }
    }
    private static Foo InitialFooReturner()
    {
        innerFoo = new Foo();
        fooReturnHandler = new FooReturner(NewFooReturner); 
        return innerFoo;
    }

    private static Foo NewFooReturner()
    {
        return innerFoo;
    }

}

简而言之 - Instance返回一个委托方法。委托最初设置为方法 初始化您的实例,然后将委托更改为指向一个简单的Return方法。

现在,我觉得我的工作并不可怕,但我对自己很棒没有任何自负。我没有在任何地方看到这个代码的例子。

因此,我得出的结论是我错过了一些东西。重要的东西。要么整个​​问题太过微不足道,要么不必考虑太多,或者这会造成毁灭宇宙的可怕事情。或者我搜索失败,因此没有看到 数百名开发人员使用这种方法。无论如何,还有什么东西。

我希望Stack Overflow这里的优秀人员可以提醒我什么(不管是否应该使用Singleton的争议)。

编辑澄清:

这不是性能代码(尽管如果设计主动降低了传统模型以外的性能,那么知道它会很有趣)。

它纯粹是作为概念证明编写的,我进一步意识到它不是正确的线程安全。有什么理由不能通过它的性质使它成为线程安全的吗?

7 个答案:

答案 0 :(得分:31)

This is the canonical, thread safe, lazy Singleton pattern in C#

public sealed class Singleton
{
    Singleton(){}
    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }        
    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() {}    
        internal static readonly Singleton instance = new Singleton();
    }
}

答案 1 :(得分:10)

为了防止必须复制单例代码,您可以将类型设为通用的,如下所示:

public abstract class Singleton<T>
    where T: class, new()
{
    public static T Instance
    {
        get { return Nested.instance; }
    }

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() { }

        internal static readonly T instance = new T();
    }
}

public sealed class MyType : Singleton<MyType>
{
}

class Program
{
    static void Main()
    {
        // two usage pattterns are possible:
        Console.WriteLine(
            ReferenceEquals(
                Singleton<MyType>.Instance, 
                MyType.Instance
            )
        );
        Console.ReadLine();
    }
}

答案 2 :(得分:4)

你有没有测量过表现?

您是否认为额外的函数调用比if?

便宜

我同意其他人使用静态ctor很适合这种初始化。这也将摆脱你所拥有的固有竞争条件.net保证静态构造函数只会被调用一次。

答案 3 :(得分:1)

  

无效率的全部问题:......

效率低下?

这些指令将导致汇编代码的速度非常快。我完全相信通过尝试“优化”这一点没有任何好处。即使你想出更快的东西,也会产生很大的复杂性。

除非您确实有充分的证据证明此代码会影响您的效果,否则您应该使用最简单的方法来解决您的问题。

答案 4 :(得分:1)

我刚刚开始使用c#编程(来自C ++,这是一种新鲜空气),这就是我用来实现单例模式的方法。

public sealed class MyClass
{    
    #region make singleton

    static readonly Lazy<MyClass> _singleton =
        new Lazy<MyClass>(() => new MyClass());

    public static MyClass Singleton
    {
        get { return _singleton.Value; }
    }

    private MyClass() { Initialize() };

    #endregion

    Initialize() { /*TODO*/ };
}

答案 5 :(得分:1)

我发现创建单例的最佳方法是:

public class Singleton
{
    static public Singleton Instance { get; } = new Singleton();
    private Singleton() { ... }
}

它非常简洁,更重要的是,线程安全,在应用程序成熟时检测和修复会非常麻烦。

更新:显示它是懒惰的......

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingletonTest
{
    class MySingleton
    {
        static public MySingleton Instance { get; } = new MySingleton();

        private MySingleton() { Console.WriteLine("Created MySingleton"); }

        public void DoSomething() { Console.WriteLine("DoSomething"); }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Main");

            MySingleton.Instance.DoSomething();
        }
    }
}

输出:

Starting Main
Created MySingleton
DoSomething

答案 6 :(得分:0)

我总是使用这个常规(非懒惰)(你可以像其他例子那样嵌套):(需要using System.Reflection;

public class SingletonBase<T> where T : class
{
    static SingletonBase()
    {
    }

    public static readonly T Instance = 
        typeof(T).InvokeMember(typeof(T).Name, 
                                BindingFlags.CreateInstance | 
                                BindingFlags.Instance |
                                BindingFlags.Public |
                                BindingFlags.NonPublic, 
                                null, null, null) as T;
}