C# C中静态构造函数的潜在陷阱#
我的问题是在重构一个只包含要声明为C# C中静态构造函数的潜在陷阱#,c#,.net,static,clr,C#,.net,Static,Clr,我的问题是在重构一个只包含要声明为static类的静态方法的类之后,在启动应用程序时遇到了奇怪的问题 我没有进行任何彻底的调查,但似乎由于某种原因,静态构造函数中的一些调用没有完成 因此,我想知道在C#中使用静态构造函数时会有哪些陷阱?更具体地说,是否有任何事情应该不惜一切代价避免,而不是在静态构造函数中使用?是的,存在一些陷阱,主要与初始化类的时间有关。基本上,带有静态构造函数的类不会被标记为beforefieldinit标志,这允许运行时稍后对其进行初始化 查看更多详细信息。静态构造函数有几
static
类的静态方法的类之后,在启动应用程序时遇到了奇怪的问题
我没有进行任何彻底的调查,但似乎由于某种原因,静态构造函数中的一些调用没有完成
因此,我想知道在C#中使用静态构造函数时会有哪些陷阱?更具体地说,是否有任何事情应该不惜一切代价避免,而不是在静态构造函数中使用?是的,存在一些陷阱,主要与初始化类的时间有关。基本上,带有静态构造函数的类不会被标记为
beforefieldinit
标志,这允许运行时稍后对其进行初始化
查看更多详细信息。静态构造函数有几个陷阱。例如,如果是静态构造函数,则无论何时访问其任何成员,都会继续获得
TypeInitializationException
如果静态构造函数抛出异常,运行时将不会再次调用它,并且在程序运行的应用程序域的生命周期内,该类型将保持未初始化状态
通常,静态类应该只在无状态场景中使用,在这种场景中,您不需要任何初始化。如果需要初始化类,最好使用,可以在首次访问时使用:
public class MyClass
{
private static readonly Lazy<MyClass> current =
new Lazy<MyClass>(() => new MyClass());
public static MyClass Current
{
get { return current.Value; }
}
private MyClass()
{
// Initialization goes here.
}
public void Foo()
{
// ...
}
public void Bar()
{
// ...
}
}
static void Main(string[] args)
{
MyClass.Current.Foo(); // Initialization only performed here.
MyClass.Current.Bar();
MyClass.Current.Foo();
}
在上面的示例中,新线程需要访问定义为其回调的空匿名函数
{}
。但是,由于匿名函数在幕后编译为MyClass
的另一个私有方法,因此在MyClass
类型初始化之前,新线程无法访问它。而且,由于MyClass
静态构造函数需要等待新线程首先完成(因为thread.Join()
),死锁随之发生。这不是问题的答案,但是对于注释来说太长了,所以我在这里提供它
由于我不知道静态类构造,因此我使用以下方案(简化)为我提供了单例:
public class SomeSingleton {
static _instance;
static public SomeSingleton Instance {
get {
if (_instance==null) {
_instance=new SomeSingleton();
}
return _instance;
}
}
}
以后,你用
SomeSingleton.Instance.MyProp = 3;
第一次使用实例
成员将构造您的单例
我想这是可以的,因为如果有许多这样的类是按正确的顺序进行实例化的,那么单例就可以了。它没有回答这个问题。。。静态类与单例不同(例如,不能将静态类作为参数传递,这可以通过单例来实现)。您的初始化不是线程安全的。如果多个线程同时访问
Instance
属性,则它们可能会得到不同的“singleton”实例。在特定情况下,这可能是一个问题,也可能不是,但它总体上打破了单例范式。如果您在.NET4(或更高版本)上,您应该切换到惰性
;如果没有,则应该考虑使用<代码>锁定>代码>来同步初始化。除了构造函数之外,还有什么异常吗?例如,什么可以解释我所经历的类似“死锁”的情况?静态类型是否在幕后涉及任何锁定?第一个示例中的锁定与这些行之间是否有任何区别<代码>私有静态只读惰性当前;静态MyClass{current=new Lazy(()=>new MyClass());}(很抱歉,似乎无法正确设置格式:)@Mark:我相信两者是等效的。静态构造函数所做的唯一一件事就是将Lazy
分配给静态字段(不初始化它),这样它就不会失败(即使MyClass()
构造函数抛出异常)。在这两种情况下,只有在第一次调用MyClass.Current
时才初始化单例。感谢完整的示例!对于那些想知道上述单例是否是线程安全的和“最佳”解决方案(这是隐含的,但我希望是明确的)的人来说,答案是肯定的。我很高兴看到你的编辑。我正试图做这件事,却不明白为什么它不起作用。非常感谢!
SomeSingleton.Instance.MyProp = 3;