29 July 2010 - 11:50 PM / by Dominic Pettifer. 3 Comments for Static Variable Gotchas - Are Static Variables in Base Classes Shared In Derived Sub Classes?.
Development Gotchas - Something that caught me out recently is the behaviour of static variables in C# classes, and how they behave in derived classes. Also how does this differ with static variables in Generic<T> base classes? Finally, we use this understanding to create a generic base Singleton class.
First consider the following base class that declares a static int:
public abstract class Base
{
private static int MyInt = 0;
public int StaticValue
{
get { return MyInt; }
set { MyInt = value; }
}
}Then we define two sub types like so:
public class DerivedA : Base { }
public class DerviedB : Base { }Now we run this code:
DerivedA drvA = new DerivedA();
DerviedB drvB = new DerviedB();
for (int i = 0; i < 3; i++)
{
drvA.StaticValue++;
drvB.StaticValue += 5;
Console.WriteLine("DerivedA: " + drvA.StaticValue);
Console.WriteLine("DerivedB: " + drvB.StaticValue);
}Take a moment to think what the output is. You should get something like this:
DerivedA: 6 DerivedB: 6 DerivedA: 12 DerivedB: 12 DerivedA: 18 DerivedB: 18
The reason is because the static ‘MyInt’ variable declared in Base type is shared with all classes that derive from it. DerivedA and DerivedB won’t get their own copies of MyInt. So to answer the question: Yes, static variables are shared by derived clases. This is generally well understood in the .NET world, including by myself before I embarked on this article. It’s Generic<T> types that tripped me up.
Now consider the following generic base class:
public abstract class BaseGeneric<T>
{
private static int MyInt = 0;
public int StaticValue
{
get { return MyInt; }
set { MyInt = value; }
}
}Literally all we’ve done is replace ‘Base’ with ‘BaseGeneric<T>’ otherwise it’s the same base class as before. Now we derive 2 types from it:
public class DerivedGenericA : BaseGeneric<string> { }
public class DerivedGenericB : BaseGeneric<int> { }Note in one we fill in the T type as string, and int in the other. Now we run the following code:
DerivedGenericA drvA = new DerivedGenericA();
DerivedGenericB drvB = new DerivedGenericB();
for (int i = 0; i < 3; i++)
{
drvA.StaticValue++;
drvB.StaticValue += 5;
Console.WriteLine("DerivedGenericA: " + drvA.StaticValue);
Console.WriteLine("DerivedGenericB: " + drvB.StaticValue);
}Take a moment to think what the output will be. It will output the following:
DerivedGenericA: 1 DerivedGenericB: 5 DerivedGenericA: 2 DerivedGenericB: 10 DerivedGenericA: 3 DerivedGenericB: 15
This is strange. They don’t seem to be sharing the same static variable even though they derive from the same class, what is going on? How are generic types being treated differently?
A clue is in the class declaration itself:
public class DerivedGenericA : BaseGeneric<string> { }
public class DerivedGenericB : BaseGeneric<int> { }In one we’re filling out the T type as string and int in the other. This effectively creates two different base types. Basically BaseGeneric<string> is not the same type as BaseGeneric<int> and because they’re not the same type, they don’t share static variables. We can see this if we use the same T type in both derived classes:
public class DerivedGenericA : BaseGeneric<string> { }
public class DerivedGenericB : BaseGeneric<string> { }...and we run the same code above to print out the static value:
DerivedGenericA: 6 DerivedGenericB: 6 DerivedGenericA: 12 DerivedGenericB: 12 DerivedGenericA: 18 DerivedGenericB: 18
...because now they both derive from the same base type of BaseGeneric<string>
We can use this knowledge to our advantage if we want to create a Generic base class that forces each derived class to be a Singleton (a helper for easily creating Singleton classes).
public abstract class SingletonBase<T> where T : SingletonBase<T>
{
private static volatile T _instance = null;
private static volatile object _syncObject = new object();
public static T Instance()
{
if (_instance == null)
{
lock (_syncObject)
{
if (_instance == null)
{
Type teesType = typeof(T);
try
{
_instance = (T)teesType.InvokeMember(teesType.Name,
BindingFlags.CreateInstance | BindingFlags.Instance |
BindingFlags.NonPublic, null, null, null,
CultureInfo.InvariantCulture);
}
catch (MissingMethodException)
{
string message = teesType.FullName +
" must use either a private or protected " +
"constructor to be a Singleton.";
throw new TypeLoadException(message);
}
}
}
}
return _instance;
}
}We’re storing the single instance as a static property, but since the base is a generic type, this static variable won’t get shared amongst the derived types, so we can create multiple singleton classes. We’re using reflection to instantiate the derived class in order to get around the classes inaccessible protected/private constructor, we’re also enforcing that the derived class must use a protected or private default constructor in the first place (Note: Reflection code came from CodeBender, cheers!) An implementation is below:
public class ConfigData : SingletonBase<ConfigData>
{
protected ConfigData()
{
// Initialise singleton (guaranteed to only run once)
DatabaseConnection = WebConfigurationManager
.ConnectionStrings["DbConn"].ConnectionString;
}
public string DatabaseConnection { get; protected set; }
public int MaxRecords { get; set; }
}Voilà, instant singleton, we just extend SingletonBase with the generic type being the derived singleton itself, and use it like this:
ConfigData data1 = ConfigData.Instance();
ConfigData data2 = ConfigData.Instance();
data2.MaxRecords = 9999;
data1.MaxRecords = 10;
Console.WriteLine("MaxRecords: " + data2.MaxRecords);
Console.WriteLine("Both point to the same instance: " + (data1 == data2));Which will output:
MaxRecords: 10 Both point to the same instance: True
@Dilip I tried:
public class DerivedGenericA : BaseGeneric<string> { }
public class DerivedGenericB : BaseGeneric<Stream> { }...like you said but it still yeilded:
DerivedGenericA: 1 DerivedGenericB: 5 DerivedGenericA: 2 DerivedGenericB: 10 DerivedGenericA: 3 DerivedGenericB: 15
...I also tried two different value types. So reference vs. value types doesn't seem to make a difference.
Posted on 2 August 2010 - 5:41 PM / by Dominic Pettifer (Administrator)
I stand corrected then. I remember reading somewhere that reference types share a single generated code with only the types being substituted because its just a pointer to an opaque object. Value types on the other hand, can vary in their size and hence code needs to be generated every time you close a generic type with a value type.
That obviously doesn't apply to member/static variables -- just operations/methods.
Posted on 2 August 2010 - 8:53 PM / by Dilip
Hi I am a big reader, would really appreciate an invite. Your blog is very nice and I really enjoy the style and content. THanks
Posted on 30 December 2011 - 5:58 AM / by University T Shirt printing
This is a very useful script! This good stuff can be properly used for my custom writing paper in university. Thank you for sharing.
Posted on 25 January 2012 - 4:25 PM / by university essay
Thanks for great explanation and much informative post.
Posted on 25 January 2012 - 4:28 PM / by custom writing service
all <strong><a href="http://www.monclersjackor.net/moncler-barn-c-7.html" title="Moncler Kids">Moncler Kids</a></strong> feet<br>are <strong><a href="http://www.monclersjackor.net/moncler-barn-c-7.html" title="Moncler Coats">Moncler Coats</a></strong> not<br>created<br>equal. <strong><a href="http://www.monclersjackor.net/moncler-barn-c-7.html" title="Moncler Barn">Moncler Barn</a></strong> nike <strong><a href="http://www.monclersjackor.net/" title="moncler väst">moncler väst</a></strong> <strong><a href="http://www.monclersjackor.net/" title="Moncler jackor">Moncler jackor</a></strong> n7 <p> through nikes n7 initiative, we <strong><a href="http://www.monclersjackor.net/moncler-barn-c-7.html" title="Moncler Vest">Moncler Vest</a></strong> have built an environmentally friendly performance shoe to ...
Posted on 16 October 2011 - 9:22 AM / by Moncler jacka
I think you will still end up sharing code as long as you keep using reference types. I didn't check this out but BaseGeneric<string> and BaseGeneric<Stream> should still let you share the same static variable defined in BaseGeneric<T>. Its only when you start using value types that each closed type will yield its own IL.
Posted on 2 August 2010 - 5:14 PM / by Dilip
br> <br>
<br> <br> but just to test the electrical
<br> <br> but Im guaranteed to pass the Rights
<br> <br> Third Church: Language
<br> <br> native language is Chinese friends
<br> <br> bad bad not much longer
<br> <br> better not much <a href="http://www.usjordanstore.com/air-jordan-retro-2-C33.html" title="jordan 2 shoe">jordan 2 shoe</a> better
<br> <br> the <a href="http://www.usjordanstore.com/" title="jordans for sale">jordans for sale</a> one who read the <a href="http://www.usjordanstore.com/air-jordan-retro-2-C33.html" title="michael jordan 2">michael jordan 2</a> harm broken
<br> <br> d...
Posted on 26 May 2011 - 2:26 AM / by jordan space jam
louis vuitton outlet
Posted on 28 June 2011 - 9:00 AM / by louis vuitton outlet
Newest styles of <a href="http://www.christianlouboutinreplicacl.com/"><strong>christian louboutin high heels</strong></a> in hot sale now, <a href="http://www.christianlouboutinreplicacl.com/"><strong>Christian Louboutin Knockoffs</strong></a> shoes sale now, buy <a href="http://www.christianlouboutinreplicacl.com/"><strong>christian louboutin replica</strong></a> in our online uk store .your shoes sales prices will save.
Posted on 22 September 2011 - 2:32 AM / by christian louboutin replica
Scenic Area Ke <b><a href="http://www.buyjordan11.com/">jordan retro 11</a></b> village fixed telephone <b><a href="http://www.buyjordan11.com/jordan-fusion-C56.html">jordan fusion</a></b> to a supermarket . Jiuhua police <b><a href="http://www.buyjordan11.com/jordan-flight-team-C75.html">air jordan flight team</a></b> <b><a href="http://www.buyjordan11.com/">air jordan 11</a></b> station rushed <b><a href="http://www.buyjordan11.com/jordan-fusion-C56.html">jordan fusion 4</a></b> to the are... <b><a href="http://www.buyjordan11.com/jordan-fusion-C56.html">air force jordan fusion</a></b>
Posted on 29 January 2012 - 7:36 AM / by canada goose jackets
And YouTube still auto-fucking-plays videos!! This is TWO-THOUSAND-AND-FUCKING-TWELVE FFS!!!
about 20 hours ago from webOn a side-note, YouTube's commenting system is god-awful atrocious dreadful horrible horrible horrible!! Constant meaningless error messages
about 20 hours ago from webJavaScript is slow mmmkay http://t.co/NbB4eQjw - Actually, no, it's not http://t.co/kpGEIoPO #nodejs
about 20 hours ago from webTFS: It's super expensive, so it must be brilliant, right? Like Sharepoint #tekpubtfstitlesuggestion
5:22 PM February 3rd from web