Genericsの中のStaticフィールドに関するコト

わかってみれば、当たり前だけど、ちと疑問に思って調べたコトを備忘録的に。
まずは、以下のようなコードがあったとして、

public class Hoge<T>
{
	public static int Value = 0;
}

class MainEntry
{

	static void Main(string[] args)
	{
		Hoge<Type>.Value = 200;
		Hoge<Int32>.Value = 300;
		Console.WriteLine(Hoge<Exception>.Value);
	}
}

このときどーなる買って話でして。。。結論から先に言うと、0がConsoleに出力される。
これは、規格で決まっていて、JIS X3015:2006の、25.1.4が根拠。*1
規格で決まってるのならしょーがないとはいえ、何でこんな風になっているのか自分なりに考えてみた。
多分、以下のようなこーどを許容するためじゃ無いかと思う。

public class Piyo<T>
{
	public static T Value = default(T);
}

この場合、静的フィールドの"Value"フィールドは型引数に依存するので、別個に初期化されないとおかしなコトになる。なので、このような規格になってるんだと思う。


んだは、オープン型のHogeから、生成されたクローズ型全てに共通する値を静的フィールドとして保持したいって時は、
ジェネリック型からジェネリック型を派生させることで行けるんじゃ無いかと。*2

public class Hoge
{
	public static int Value;
}

public class HogeEx<T> : Hoge
{
}

class MainEntry
{

	static void Main(string[] args)
	{
		HogeEx<Type>.Value = 200;
		HogeEx<Int32>.Value = 300;
		Console.WriteLine(HogeEx<Exception>.Value);
	}
}

こうすることで、オープン型HogeExから生成された、クローズ型全ての"Value"フィールドを一致させることが出来る。
蛇足ながら、以下のようにしたとしても、別個になるので、注意。あくまでもオープン型の内側にある主体は全てクローズ型個別に生成されると言うことなのかも

public class Piyo<T>
{
	private class Inner
	{
		public static int Value;
	}

	public static int Value
	{
		get
		{
			return Inner.Value;
		}
		set
		{
			Inner.Value = value;
		}
	}
}

class MainEntry
{

	static void Main(string[] args)
	{
		Piyo<Type>.Value = 200;
		Piyo<Int32>.Value = 300;

		Console.WriteLine(Piyo<Exception>.Value);

	}

このサンプルだと、Inncerはprivateなので、外部から不可視だけど、例えばこれがpublicになってたとき、結局アクセスするためには、Piyo.Inner.Valueのような形になるので、不整合を生まないためなんじゃないかと。
あと、外部定義の型をシングルトンにするなり、元から、static classにするなりして、そいつを参照させるなんて方法も無くは無いと思うけど*3これだと、アクセシビリティが厄介なことになる*4ので、あんまりおすすめできないかも。

*1:ちなみに、TypeInitializerの動きは、25.1.5に書いてあって、こちらも異なるクローズ型が作成されるたびに1回ずつ呼び出される。

*2:もしかしたら、属性を利用すると出来るのかもしれないけど、その辺は未調査

*3:実際こっちを最初に思いついた

*4:具体的に言うと、型の外側から値を変更できてしまう