一般的单身人士

时间:2008-12-19 11:41:03

标签: c# singleton generics

对于一般的单身人士,你们怎么看待这个?

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 个答案:

答案 0 :(得分:30)

创建单例类只是几行代码,并且由于难以制作通用单例,我总是编写这些代码行。

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

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

答案 1 :(得分:5)

嗯,它不是真正的单身 - 因为你无法控制T,你可以有尽可能多的T个实例。

(删除了线程;注意了双重检查的用法)

答案 2 :(得分:5)

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

此外,它不会禁止内部构造函数 - 因此您最终可以使用非单例。

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

基本上我不是一个粉丝 - 创建单例类很容易,而且你不应该经常这样做。单身人士是测试,脱钩等的痛苦。

答案 3 :(得分:5)

这是我使用.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;}}
   }

答案 4 :(得分:1)

合并AndreasN的答案和Jon Skeet的Singleton c#实现的“Fourth version - not quite as lazy, but thread-safe without using locks”,为什么不使用代码片段来完成所有艰苦的工作:

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

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

答案 5 :(得分:0)

通用单件工厂存在问题,因为它是通用的,您无法控制实例化的singleton类型,因此您可以永不保证您创建的实例将是应用程序中唯一的实例。

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

答案 6 :(得分:-1)

我不认为使用泛型对单身人士有用。因为您总是可以创建多个实例,因此根据定义它是单例。如果你需要一个懒惰的单身人士,并要求它成为一个真正的单身人士一个简单的解决方案(基于亚历山大的例子)

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