“静态类”;初始化";C#中的模式?
使用此模式的好处或原因是什么“静态类”;初始化";C#中的模式?,c#,static,initialization,C#,Static,Initialization,使用此模式的好处或原因是什么 public sealed class myStaticClass { private static bool _initialized; private static object _lockObject; private static string _someStaticField; private static int _anotherStaticField; private static string _nthSta
public sealed class myStaticClass
{
private static bool _initialized;
private static object _lockObject;
private static string _someStaticField;
private static int _anotherStaticField;
private static string _nthStaticField;
static myStaticClass()
{
_initialized = false;
_lockObject = new object();
}
public myStaticClass()
{
}
public static void Initialize()
{
if(!_initialized)
{
lock(_lockObject)
{
if(!_initialized)
{
//do initializing
_someStaticField = someApplicationSetting;
_anotherStaticField = anotherApplicationSetting;
_nthStaticField = nthApplicationSetting;
_initialized = true;
}
}
}
}
public static string NthStaticField
{
get {
Initialize();
return _nthOtherField;
}
}
}
如果保证在访问任何类成员之前调用静态构造函数,并且只调用一次,那么为什么不将所有初始化逻辑都放在静态构造函数中呢
编辑:我已经更新了模式,以便更好地反映发现该模式的.net framework中的类。我已经将类上的static
修饰符更改为sealed
,并且还添加了一个空的public
构造函数
顺便说一句,如果你想知道,我看到这个模式的类是
FormsAuthentication
类。这样做的唯一原因是如果初始化很昂贵(就CPU/RAM而言),或者所需的东西只在运行时后期才可用。。。此实现将初始化延迟到可能的最新时刻(第一次访问之前)。这是一种提供的功能…可能,应用程序设置在运行时稍后才可用。好的,我现在已经阅读并考虑了给出的链接,并得出结论,这个特定示例没有中断。
我将解释为什么
首先,它与CSharp深入文章中的模式不同。本文中的模式适用于单例。我介绍的模式不是单例模式,它有一个公共构造函数,但是它的所有字段都是静态的。因此,最大的区别在于csharpindepth模式返回对单例对象的引用,即使它实际上可能尚未完全实例化。关键的一点是,在构造函数完成之前,可以将实例分配给引用
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
这是csharpindepth模式,其工作原理如下
如果有3个线程A、B和C。线程A调用Instance方法,Instance为null,则获取锁。现在,在线程A创建Sigleton实例之前,线程B的实例仍然为空。但是A有锁,所以B等待。当B在等待时,线程A执行代码instance=newinstance()
。此时,instance被设置为Singleton的一个实例,但是它可能还没有实际构建这就是线程安全性中断的地方。线程C出现时,它看到实例不是null,因此实例方法返回对实例的引用但是线程A尚未完成实例的构造,因此线程C和与线程C同时进入的任何其他线程都会获得对一个dud单例实例的引用。最后A完成了,B得到了锁,但是工作现在完成了,所以它退出了
我介绍的模式有很大不同。用于双重检查的字段不是在Initialize方法中创建的实例。它是一个简单的专用静态bool
,用作开关。由于它不是对尚待构造的单例对象的引用,并且从未在该类之外访问过它,所以没有问题
如果在初始化类字段之前,在顶部将
private static bool\u initialized
开关设置为true,则会出现问题。这是代码放弃锁之前发生的最后一件事。因此,线程C不可能读取\u initialized
,并将类误认为已初始化。因此,无论如何boken都不会这样做。查找C#的“双重检查锁定”和/或“惰性初始化”。在几篇文章中有一篇很好的文章链接到,讨论了获得这种惰性(需要时一次)初始化的不同方法。(在许多情况下,发布的代码实际上不是推荐的方法之一;-)啊,这里是C#Depth的著名文章:列出了5种方法,并给出了解释@pst是正确的,但应该更加有力。这个代码被严重破坏和错误。你不能像这样安全地进行双重检查锁定!双重检查锁定的基本规则是,您测试的东西必须是您唯一变异的东西。您不能使用标志来控制双重检查锁定,然后完全改变其他变量;那绝对不能保证安全。如果您不完全了解运行时的内存模型,则不应尝试编写低锁代码;这是另一个著名的“危险破坏的错误实现的双重检查锁定模式”的例子。