我阅读了Jon Skeet关于如何实现C#单例的明确post,并遵循以下模式。请注意,我没有空的ctor。我的Ctor可能会做一些工作,比如创建和填充一个字符串数组(或者它可能会创建一些对象并将它们分配给私有变量等):
public class MyClass
{
/// <summary>
/// Get singleton instance of this class.
/// </summary>
public static readonly MyClass Instance = new MyClass();
/// <summary>
/// a collection of strings.
/// </summary>
private string[] strings;
private MyClass()
{
this.strings = new string[]
{
"a",
"b",
"c",
"d",
"e"
};
}
public void MyMethod()
{
// tries to use this.strings.
// can a null ref exception happen here when running multithreaded code?
}
}
高于线程安全吗?我问,因为我有类似的代码在asp.net appserver上运行并在日志中获得null ref异常(不确定null ref是否与上述相关 - 我认为不是 - 并且日志中的调用堆栈没有用)。
答案 0 :(得分:1)
老实说,我不明白为什么它不应该是线程安全的。特别是考虑到Jon的第四个线程安全版本基本相同。
我看到的唯一问题是你没有静态构造函数。 (这可能会导致问题,请参阅this)如果添加静态构造函数(即使它是空的),您将拥有Jon Skeet所谓的线程安全。
public class MyClass
{
public static readonly MyClass Instance = new MyClass();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static MyClass() { }
}
答案 1 :(得分:1)
根据提到的Jon Skeet文章,添加静态构造函数将导致此实现是线程安全的:
类型初始值设定项的懒惰仅在类型未使用名为beforefieldinit的特殊标志标记时由.NET保证。不幸的是,C#编译器(至少在.NET 1.1运行时中提供)标记所有没有静态构造函数的类型(即看起来像构造函数但被标记为静态的块)为beforefieldinit
(见http://csharpindepth.com/articles/general/singleton.aspx#cctor)
如你所知,它不是线程安全的。如果您执行此类操作,则会变为线程安全:
public class MyClass
{
/// <summary>
/// Get singleton instance of this class
/// </summary>
public static readonly MyClass Instance = new MyClass();
static MyClass()
{
//causes the compiler to not mark this as beforefieldinit, giving this thread safety
//for accessing the singleton.
}
//.. the rest of your stuff..
}