9

リフレクションを使用してジェネリック型のインスタンスを作成しています。

public interface IModelBuilder<TModel>
{
    TModel BuildModel();
}

public class MyModel
{
    public string Name { get; set; }
}

public class MyModelBuilder : IModelBuilder<MyModel>
{
    public MyModel BuildModel()
    {
        throw new NotImplementedException();
    }
}

実行時にわかっているのは、モデルの Type だけですMyModel。次のように、関連するモデル ビルダーのインスタンスを見つけることができます。

var modelBuilders = from t in Assembly.GetExecutingAssembly().GetTypes()
                from i in t.GetInterfaces()
                where i.IsGenericType
                        && i.GetGenericTypeDefinition() == typeof(IModelBuilder<>)
                        && i.GetGenericArguments()[0] == modelType
                select t;

var builder = Activator.CreateInstance(modelBuilders.First());

IModelBuilder<TModel>しかし、どのようにインスタンスをキャストして、の結果を呼び出して操作できるかわかりませんBuildModel()

4

1 に答える 1

20

modelTypeは単なるインスタンスであるためType、利用可能な非汎用 API がないため、自動的に行うことはできません。さまざまなオプション:

1: リフレクションを使用します (未テスト)。

object builder = Activator.CreateInstance(...);
var model=builder.GetType().GetMethod("BuildModel").Invoke(builder,null);

2: チートdynamic:

dynamic builder = Activator.CreateInstance(...);
var model = builder.BuildModel();

3: の非汎用バージョンを作成しIModelBuilder、それを使用する

1 と 2 はインターフェイスのパブリック実装に依存しており、(完全に合法的な) 明示的なインターフェイス実装では失敗することに注意してください。「1」の場合、次の方法でこれを修正できます。

var model = typeof(IModelBuilder<>).MakeGenericType(modelType)
       .GetMethod("BuildModel").Invoke(builder);

最後の卑劣なオプションは、非ジェネリック メソッドからジェネリック メソッドに切り替えることです。これにより、ジェネリック メソッド内ですべてのメンバーを直接使用できます。を介してそれを行う怠惰な方法がありますdynamic

interface ISneaky<T>
{
    T Foo { get; }
}
class Sneaky<T> : ISneaky<T>
{
    T ISneaky<T>.Foo { get { return default(T); } }
}
class Program
{
    static void Main()
    {
        Execute(typeof(int));
    }
    static void Execute(Type t)
    {
        dynamic obj = Activator.CreateInstance(
            typeof(Sneaky<>).MakeGenericType(t));
        // crafy hack to flip from non-generic code into generic code:
        Evil(obj);
    }
    static void Evil<T>(ISneaky<T> sneaky)
    {   // in here, life is simple; no more reflection
        Console.WriteLine("{0}: {1}", typeof(T).Name, sneaky.Foo);
    }
}
于 2012-06-27T12:07:10.480 に答える