任意のジェネリック型を動的に生成
ちょっとしたスニペットを置いておきます。任意のジェネリック型を動的に生成するためのメソッドです。
例えば、アセンブリ外に非公開の型についてジェネリック型を利用したいような場合等に有用です。
System.ReflectionやらSystem.Reflection.Emitを使って、あんなことやこんなことを
ごにょごにょするような場面なんかで結構お世話になってます。
/// <summary> /// 任意のジェネリック型を動的に生成します。 /// </summary> /// <typeparam name="T"> /// ジェネリック型を構築する元になるジェネリック型定義 /// 例えば、List{}やDictionary{,}など /// </typeparam> /// <param name="genericArgMetadata">ジェネリック型に必要な引数メタデータ</param> /// <returns>任意のジェネリック型のインスタンス</returns> public static object DynamicCreateGenericType(Type genericType,Type[] genericArgMetadata) { if (!genericType.IsGenericType || genericType != genericType.GetGenericTypeDefinition()) throw new ArgumentException("指定されたgenericTypeは、ジェネリック型を構築する元になるジェネリック型定義(GenericTypeDefinition)ではありません。"); var genericTypeArgumentCount = genericType.GetGenericArguments().Count(); if (genericTypeArgumentCount != genericArgMetadata.Count()) throw new ArgumentOutOfRangeException("生成するジェネリック型の引数の数と、Type[]メタデータの数が異なります。"); Type gtd = genericType.GetGenericTypeDefinition(); Type dgtype = gtd.MakeGenericType(genericArgMetadata); var dg = Activator.CreateInstance(dgtype); return dg; }
例えば、こんな感じで利用します。
動的に取得した型somethingTypeについて、List<>を生成したいってゆーシナリオとか。
var somethingType = obj.GetType().GetField("_something", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); var dynamicList = Utility.DynamicCreateGenericType(typeof(List<>), new Type[] { somethingType }); var addminfo = dynamicList.GetType().GetMethod("Add"); foreach (var value in GetSomethingInfoArray()) { addminfo.Invoke(dynamicList, new object[] { value }); }
しかし、DynamicCreateGenericTypeってネーミングはなんかイマイチですねえ。
あれ以来というもの、どうもdynamicとかいう単語には敏感である。C#4.0を連想してまう俺ガイル。
ダイナミックを取り入れることは、確かにウマウマなことが増えるわけで、嬉しっちゃーうれしいいんだけど、
それよか、C#4.0では「契約プログラミング」の機構を言語レベルでサポートして欲しいー。
それも痒いところまで手が届く感じでお願いしたい。これに尽きる。おねーげーしますAnders Hejlsberg大先生。
あ、DelphiはDelphiで言語として何かと成長していたみたいですね。結構がんばっているようですね〜。
俺のDelphiスキルは6で止まっていますがw