2011-06-08 97 views
1

我正在研究C#的单例模式,我从msdn网站上找到了这个例子。C#中的单例模式问题

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    private Singleton(){} 

    public static Singleton Instance 
    { 
     get 
     { 
     return instance; 
     } 
    } 
} 

因为Singleton实例是 由私人静态成员变量 参考,并不 发生的实例,直到类是通过对实例 属性的调用引用第一 。因此,该解决方案 实现了一种惰性 实例化属性,如在Singleton的 Design Patterns表单中。

我不是很确定的时候会记忆将得到前甚至将其分配给

private static readonly Singleton instance 

1)它会发生在实例属性被称为还是?

2)我需要强制类创建一个新的内存有时清除其内容。使用set安全吗?

set 
{ 
instance = null; 
} 
+3

*懒实例*的形式说明了一切 – V4Vendetta 2011-06-08 11:37:30

+1

在这情况下(非常错误的)'集合{}'从何而来? – 2011-06-08 11:48:10

+1

你的第二个问题很有意义。 – CodesInChaos 2011-06-08 11:52:12

回答

6

在您提供的示例代码中,将在第一次访问该类时创建单例实例。这意味着你的例子在Instance第一次被调用的时候。

更多的洞察力,你可以在乔恩斯基特的文章Implementing the Singleton Pattern in C#寻找,查看方法4

基本上,为了实现真正的偷懒行为像

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    static Singleton(){} 
    private Singleton(){} 

    public static Singleton Instance 
    { 
     get { return instance; } 
    } 
} 

就足够了。

(但不管怎么说,全面和更好的概述,可以提及的文章中找到。)

编辑
其实,当它从提到的文章下面的实例,但不保证创建在第一次访问时,由于BeforeFiledInit标记。你需要添加一个空的静态构造函数,这样保证是懒惰的。否则,该实例将在程序启动和第一次访问之间的某个非特定时间创建。 (.NET运行库2.0是已知有更渴望的策略,所以你可能无法得到的偷懒行为。)

从上述文章引用:

类型初始化的懒惰只受担保.NET时类型没有标记一个叫做beforefieldinit的特殊标志。不幸的是,C#编译器[...]标记所有没有静态构造函数的类型为beforefieldinit

EDIT 2
如果你想单独的对象进行清理,你应该包括这个功能到类Singleton本身。

删除属性值将有效地使您的班级不再是单身人士!想象一下,有人访问单例并获取单例实例。之后,您将该物业设置为nullSingleton类的现有对象不会消失,因为它仍然有一个参考!因此,下次您访问Instance属性时,将创建另一个Singleton类的实例。所以你失去了两件事:你的对象不再是单身(因为你有两个同时存在的实例),并且内存也没有被清除。

0

它说,在您发布的报价:直到 类首先由 呼叫参考实例属性

所以

的实例不会发生......每当你请致电.Instance,或者之前的某个时间点。

+0

问题是这个报价不能被规范保证。这导致了“或者在某个时刻之前”部分。 – CodesInChaos 2011-06-08 11:50:11

0

第一次访问静态成员之前,以及静态构造函数(如果有)被调用之前,会初始化静态成员。

Read more on MSDN

3

C#的规范说:一类

10.5.5.1静态字段初始化

在静磁场用变量初始化对应于在文本执行的任务序列它们出现在类声明中的顺序。如果类中存在静态构造函数(第10.12节),则在执行静态构造函数之前立即执行静态字段初始化函数。否则,静态字段初始值设定项会在第一次使用该类的静态字段之前的执行相关时间执行。

即他们只保证你得到的是它发生在instance字段被读取之前。但它可能发生得更早。

如果你想保证它,它不跑的比属性的第一次访问你越早将需要添加静态构造函数(可能为空):

的静态构造函数封闭类类型在给定的应用程序域中最多执行一次。静态构造函数的执行是由应用程序域中发生以下第一个事件触发的:
·创建了类类型的实例。
·引用了类类型的任何静态成员。


作为一个边节点:我注意到,使用DI当它是很少需要使用真正的单身。简单地告诉DI应该创建一个实例就足够了。这是非常好的,如果你稍后决定你想要多于一个实例,那么事实上它是一个单例不会被所有使用它的代码烘焙。

6

当类本身被加载时,单实例实例将被加载到内存中,也就是说,可以调用它的方法开始执行。调入该类的实际行不必实际执行。这是一个非常微小的区别,但是当静态构造函数或静态字段初始值设定项可能会引发错误(您不在此处)时会创建难以调试的问题。

这在.NET 4中使用新的Lazy<T>实现得到修复。

http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx

public sealed class Singleton 
{ 
    private static readonly Lazy<Singleton> lazy = 
     new Lazy<Singleton>(() => new Singleton()); 

    public static Singleton Instance { get { return lazy.Value; } } 

    private Singleton() 
    { 
    } 
} 

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