2012-04-25 10 views
4

タイプパラメータからジェネリッククラスを作成する方法はありますか?タイプパラメータから汎用クラス

私はこのようなものがあります:私が欲しいもの

public class SomeClass 
{ 
    public Type TypeOfAnotherClass { get; set; } 
} 

public class OneMoreClass 
{ 
} 

public class GenericClass<T> 
    where T : class 
{ 
    public void DoNothing() {} 
} 

public class GenericClass 
{ 
    public static GenericClass<T> GetInstance<T>(T ignored) 
     where T : class 
    { 
     return new GenericClass<T>(); 
    } 
} 

がタイプからGenericClassを作成することです。例:

var SC = new SomeClass(); 
SC.TypeOfAnotherClass = typeof(OneMoreClass); 
var generic = GenericClass.GetInstance(SC.TypeOfAnotherClass); 

Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic.GetType()); 

ここでは、私はGenericClass<OneMoreClass>のインスタンスを取得するために期待するが、私はまた、その型のインスタンスを使用してみましたGenericClass<Type>

を取得します。例:

var generic = GenericClass.GetInstance(Activator.CreateInstance(SC.TypeOfAnotherClass)); 

私は

GenericClass<object>を取得し、この時、このタスクを達成する方法はありますか?

答えて

7

public class GenericClass 
{ 
    public static GenericClass<T> GetInstance<T>(T ignored) 
     where T : class 
    { 
     return new GenericClass<T>(); 
    } 

    public static GenericClass<T> GetInstance<T>() 
     where T : class 
    { 
     return new GenericClass<T>(); 
    } 
} 

Thの使用状況:

var generic1 = GenericClass.GetInstance<OneMoreClass>(); 
    var generic2 = GenericClass.GetInstance(new OneMoreClass()); 

アサーション私が正しくあなたを理解している場合、これはあなたが探しているものです)をビルド時に使用すると、それを使用するだけです。

var generic = GenericClass.GetInstance<OneMoreClass>(); 

しかし、私はあなたがビルド時にそれを知らず、実行時にtypeを取得しなければならないと仮定しています。 あなたが反射でそれを行うことができますが、それはかなりではない、と遅いです:

public class GenericClass 
{ 
    public static object GetInstance(Type type) 
    { 
     var genericType = typeof(GenericClass<>).MakeGenericType(type); 
     return Activator.CreateInstance(genericType); 
    } 
} 

あなたがビルド時に結果の型を知らないので、あなたはobject(またはdynamicが、何かを返すことはできません。 )をメソッドから取得します。 100倍遅くオーバー

With Reflection: 243ms. 
Without Reflection: 2ms. 

ので、少し:ここ


public class GenericClass 
{ 
    public static object GetInstance(Type type) 
    { 
     var genericType = typeof(GenericClass<>).MakeGenericType(type); 
     return Activator.CreateInstance(genericType); 
    } 

    public static GenericClass<T> GetInstance<T>() 
     where T : class 
    { 
     return new GenericClass<T>(); 
    } 
} 

    [Test] 
    public void CanMakeGenericViaReflection_ButItsSlow() 
    { 
     var timer = new Stopwatch(); 
     var SC = new SomeClass(); 
     SC.TypeOfAnotherClass = typeof(OneMoreClass); 

     timer.Start(); 
     for (int x = 0; x < 100000; x++) 
     { 
      GenericClass.GetInstance(SC.TypeOfAnotherClass); 
     } 
     timer.Stop(); 
     Console.WriteLine("With Reflection: " + timer.ElapsedMilliseconds + "ms."); 

     timer.Restart(); 
     for (int x = 0; x < 100000; x++) 
     { 
      GenericClass.GetInstance<OneMoreClass>(); 
     } 
     timer.Stop(); 
     Console.WriteLine("Without Reflection: " + timer.ElapsedMilliseconds + "ms."); 
    } 

結果(10万が作成されます)どのくらいの時間がかかります。

ジェネリックについて注意する実物はジェネリックで<T> SはC#コンパイラによってビルド時に解決され、実際のクラス名が挿入されていることです。ランタイムまでそれを延期しなければならないと、パフォーマンス価格を支払うことになります。

+0

どのくらい遅いですか? – Gabe

+0

@Gabe - リフレクションを使用した場合のパフォーマンスヒットを表示するために、私の答えにさらに追加しました。 – CodingWithSpike

+0

「遅い」とは「2マイクロ秒かかる」という意味です。 1秒間に数千回だけ行うのはかなり速いですが、何百万回も行う必要がある場合は遅すぎます。 – Gabe

1

ここでは正確に何を求めているのか分かりません。 OneMoreClass(あなたが実際にしたいタイプを知っていれば

Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic1.GetType()); 
Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic2.GetType()); 
関連する問題