对于一般的单身人士,你们怎么看待这个?
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);
}
}
}
}
答案 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