19

My question comes after refactoring a class that contained only static methods to be declared as a static class, and experiencing weird issues when starting the application.

I have not performed any thorough investigation but it seems that some call being made from within the static constructor does not complete for some reason.

So, I would like to know where there are any pitfalls when using static constructors in C#? More specifically, are there any things that should be avoided at all cost and not be used from within the static constructor?

lysergic-acid
  • 19,570
  • 21
  • 109
  • 218

3 Answers3

27

There are several pitfalls to static constructors. For example, if a static constructor throws an exception, you would continue getting a TypeInitializationException whenever you access any of its members.

If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.

In general, static classes should only be used in stateless scenarios where you won’t need any initialization. If your class needs to be initialized, you might be better off using the singleton pattern, which can be lazily initialized on first access:

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();
}

Edit: I did some further reading up on the matter, and it appears that static constructors do cause deadlocks if you perform blocking operations (e.g. asynchronous callbacks or thread synchronization) within them.

The CLR internally uses locking to prevent type initializers (static constructors) from being executed multiple times concurrently. Thus, if your static constructor attempts to access another member of its declaring type from another thread, it would inevitably deadlock. Since “another member” could be an anonymous function declared as part of a PLINQ or TPL operation, these bugs can be subtle and hard to identify.

Igor Ostrovsky (MSFT) explains this in his Static constructor deadlocks article, providing the following example of a deadlock:

using System.Threading;

class MyClass
{
    static void Main() { /* Won’t run... the static constructor deadlocks */  }

    static MyClass()
    {
        Thread thread = new Thread(arg => { });
        thread.Start();
        thread.Join();
    }
}

In the above example, the new thread needs to access the empty anonymous function, { }, defined as its callback. However, since the anonymous function is compiled as another private method of MyClass behind the scenes, the new thread cannot access it before the MyClass type initializes. And, since the MyClass static constructor needs to wait for the new thread to complete first (because of thread.Join()), a deadlock ensues.

Douglas
  • 53,759
  • 13
  • 140
  • 188
  • Is there anything other than exceptions thrown inside the constructor? For instance, what could explain the "deadlock" like scenario i am experiencing? Is any locking involved with static types somehow behind the scenes? – lysergic-acid May 06 '12 at 10:21
  • Is there any difference between what you have in the first example and these lines instead? `private static readonly Lazy current; static MyClass { current = new Lazy(() => new MyClass()); }` (sorry can't seem to get the formatting right :) ) – Mark Apr 23 '14 at 04:24
  • @Mark: I believe the two are equivalent. The only thing your static constructor does is assign the `Lazy` to the static field (*without* initializing it), so it has no chance of failing (even if the `MyClass()` constructor throws an exception). In both cases, the singleton is only initialized (lazily) the first time that `MyClass.Current` is called. – Douglas Apr 23 '14 at 19:41
  • Thanks for the complete example! For those of you who are wondering if the above singleton is thread safe and the "best" solution (it's implied, but I want explicit), the answer is yes. See [Jon Skeet's article on singletons in C#](http://csharpindepth.com/Articles/General/Singleton.aspx) or [this similar S.O. question](http://stackoverflow.com/a/12316461/151325). – goku_da_master Feb 19 '15 at 01:32
  • I am SO glad I ran across your edit. I was attempting to do this very thing and couldn't figure out why it wasn't working. Thanks so much! – Matt Davis May 31 '16 at 20:55
3

Yes, there are some pitfalls, mostly related to when the class is initialized. Basically, a class with a static constructor will not be marked with the beforefieldinit flag, which allows the runtime to initialize it at a later time.

Have a look at this article for more details.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
0

This is not an answer to the question, but it's too long for a comment, so I offer it here...

Since I didn't know for static class construct, I have used following scheme (simplified) to provide me with singletons:

public class SomeSingleton {
    static _instance;
    static public SomeSingleton Instance {
        get {
            if (_instance==null) {
                _instance=new SomeSingleton();
            }
            return _instance;
        }
    }
}

Later, you use

SomeSingleton.Instance.MyProp = 3;

And first usage of the Instance member will construct your singleton.

I guess that it is OK since instantiation of the singletons if there are many of such classes is done in proper order.

Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
  • 1
    It doesn't answer the question... and a static class is *not* the same as a Singleton (e.g. you can't pass a static class as a parameter, which you can do with a singleton) – Thomas Levesque May 05 '12 at 21:30
  • 5
    Your initialization is not thread-safe. If the `Instance` property is accessed concurrently by multiple threads, they might get different instances of the “singleton”. This may or may not be an issue in specific cases, but it breaks the singleton paradigm in general. If you’re on .NET 4 (or later), you should switch to `Lazy`; if not, you should consider using `lock` to synchronize initialization. – Douglas May 05 '12 at 22:01