So here's an excerpt from one of my classes:
[ThreadStatic] readonly static private AccountManager _instance = new AccountManager(); private AccountManager() { } static public AccountManager Instance { get { return _instance; } }
As you can see, it's a singleton-per-thread - i.e. the instance is marked with the ThreadStatic attribute. The instance is also instantiated as part of static construction.
So that being the case, how is it possible that I'm getting a NullReferenceException in my ASP.NET MVC application when I try to use the Instance property?
Use the readonly keyword in C# The readonly keyword can be used to define a variable or an object as readable only. This means that the variable or object can be assigned a value at the class scope or in a constructor only.
Only the initialization of static fields are thread safe, the value is not! To guarantee thread safety on static fields, add readonly (read initonly). This guarantees that the value cannot be overwritten (if you are not using a collection of some sort that is).
In C#, you can use a readonly keyword to declare a readonly variable. This readonly keyword shows that you can assign the variable only when you declare a variable or in a constructor of the same class in which it is declared.
A Static Readonly type variable's value can be assigned at runtime or assigned at compile time and changed at runtime. But this variable's value can only be changed in the static constructor. And cannot be changed further. It can change only once at runtime.
Quoting MSDN ThreadStaticAttribute:
Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization occurs only once, when the class constructor executes, and therefore affects only one thread. If you do not specify an initial value, you can rely on the field being initialized to its default value if it is a value type, or to a null reference (Nothing in Visual Basic) if it is a reference type.
This is a confusing part of the ThreadStatic
attribute. Even though it creates a value per thread, the initalization code is only run on one of the threads. All of the other threads which access this value will get the default for that type instead of the result of the initialization code.
Instead of value initialization, wrap it in a property that does the initialization for you.
[ThreadStatic] readonly static private AccountManager _instance; private AccountManager() { } static public AccountManager Instance { get { if ( _instance == null ) _instance = new AccountManager(); return _instance; } }
Because the value _instance
is unique per thread, no locking is necessary in the property and it can be treated like any other lazily initialized value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With