6

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

私はこのようなものを持っています:

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>

このタスクを実行する方法はありますか?

4

2 に答える 2

10

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,000の作成の場合)

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.");
    }

結果:

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

つまり、100倍強遅くなります。

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

于 2012-04-25T16:13:22.257 に答える
2

あなたがここで正確に何を求めているのかわかりません。私があなたを正しく理解していれば、これはあなたが探しているものです:

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>();
    }
}

使用法:

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

アサーション:

Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic1.GetType());
Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic2.GetType());
于 2012-04-25T16:07:25.317 に答える