代码之家  ›  专栏  ›  技术社区  ›  Simon Hughes

一个普通的单例

  •  19
  • Simon Hughes  · 技术社区  · 16 年前

    对于一个普通的单身汉你们怎么看这个?

    using System;
    using System.Reflection;
    
    // Use like this
    /*
    public class Highlander : Singleton<Highlander>
    {
        private Highlander()
        {
            Console.WriteLine("There can be only one...");
        }
    }
    */
    
    public class Singleton<T> where T : class
    {
        private static T instance;
        private static object initLock = new object();
    
        public static T GetInstance()
        {
            if (instance == null)
            {
                CreateInstance();
            }
    
            return instance;
        }
    
        private static void CreateInstance()
        {
            lock (initLock)
            {
                if (instance == null)
                {
                    Type t = typeof(T);
    
                    // Ensure there are no public constructors...
                    ConstructorInfo[] ctors = t.GetConstructors();
                    if (ctors.Length > 0)
                    {
                       throw new InvalidOperationException(String.Format("{0} has at least one accesible ctor making it impossible to enforce singleton behaviour", t.Name));
                    }
    
                    // Create an instance via the private constructor
                    instance = (T)Activator.CreateInstance(t, true);
                }
            }
        }
    }
    
    7 回复  |  直到 8 年前
        1
  •  30
  •   Alastair Pitts    11 年前

    创建一个singleton类只是几行代码,而且由于很难创建一个通用的singleton,我总是编写这些代码行。

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

    这个

    private static Singleton _instance = new Singleton();
    

    行消除了锁定的需要,因为静态构造函数是线程安全的。

        2
  •  5
  •   Marc Gravell    16 年前

    好吧,这不是单身的-因为你不能控制 T ,可能有很多 T 你喜欢的实例。

    (拆下的螺纹圈;注意重复检查的用法)

        3
  •  5
  •   Jon Skeet    16 年前

    我删除了以前的答案,因为我没有注意到检查非公共构造函数的代码。但是,这是一个仅在执行时执行的检查-没有 编译时间 支票,这是对它的打击。它还依赖于有足够的访问权来调用非公共构造函数,这增加了一些限制。

    此外,它并不禁止 内部的 构造器-这样就可以以非单例结束。

    为了简单的线程安全,我个人也会在静态构造函数中创建实例。

    基本上,我不太喜欢创建单例类——创建单例类很容易,而且无论如何你也不应该经常这样做。单例测试对于测试、分离等来说是一种痛苦。

        4
  •  5
  •   Alexandr    12 年前

    这是我使用.NET 4的观点

    public class Singleton<T> where T : class, new()
        {
            Singleton (){}
    
            private static readonly Lazy<T> instance = new Lazy<T>(()=> new T());
    
            public static T Instance { get { return instance.Value; } } 
        }
    

    它的用途如下:

       public class Adaptor
       {
         public static Adaptor Instance { get { return Singleton<Adaptor>.Instance;}}
       }
    
        5
  •  1
  •   Luis Vaccaro    11 年前

    合并Andreans答案和Jon Skeet's“ Fourth version - not quite as lazy, but thread-safe without using locks “对于单例C实现,为什么不使用代码片段来完成所有繁重的工作:

    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
        <CodeSnippet Format="1.0.0">
            <Header>
                <Title>Singleton Class</Title>
                <Author>TWSoft</Author>
                <Description>Generates a singleton class</Description>
                <SnippetTypes>
                    <SnippetType>Expansion</SnippetType>
                </SnippetTypes>
                <Keywords>
                    <Keyword>Singleton</Keyword>
                </Keywords>
                <Shortcut>singleton</Shortcut>
            </Header>
            <Snippet>
                <Declarations>
                    <Literal>
                        <ID>ClassName</ID>
                        <ToolTip>Replace with class name</ToolTip>
                        <Default>MySingletonClass</Default>
                    </Literal>
                </Declarations>
    
                <Code Language="CSharp">
                    <![CDATA[
                    public class $ClassName$
                    {
                        #region Singleton
                        static readonly $ClassName$ mInstance = new $ClassName$();
    
                        // Explicit static constructor to tell C# compiler
                        // not to mark type as beforefieldinit
                        static $ClassName$()
                        {
                        }
    
                        private $ClassName$()
                        {
                        }
    
                        public static $ClassName$ Instance
                        {
                            get { return mInstance; }
                        }
                    #endregion
                    }
                    ]]>
                </Code>
            </Snippet>
        </CodeSnippet>
    </CodeSnippets>
    

    然后您可以将其保存到.snipt文件中,并将其添加到vs-ide(工具->代码段管理器)

        6
  •  0
  •   Mehdi Dehghani    8 年前

    通用的单例工厂有问题,因为它是通用的,所以您不能控制 singleton 已实例化的类型,因此可以 永远不保证 您创建的实例将是应用程序中唯一的实例。

    所以, 不能创建通用的单例工厂-它会破坏模式本身。

        7
  •  -1
  •   Wouter    8 年前

    我不认为使用仿制药对单身汉有用。因为您总是可以创建多个实例,因此 根据定义,一个单件。如果你需要一个懒惰的单例,并要求它是一个真正的单例,一个简单的解决方案(基于Alexandr的例子)

    public sealed class Adaptor
    {
        private static readonly Lazy<Adaptor> instance = new Lazy<Adaptor>(() => new Adaptor());
    
        public static Adaptor Instance { get { return instance.Value; } }
    
        private Adaptor() { }
    }
    

    不能将其正确重构为单独的泛型单例。

    参见: http://csharpindepth.com/Articles/General/Singleton.aspx