转换使用Reflection创建的泛型类型实例

Ben*_*ter 7 c# reflection

我正在使用反射创建泛型类型的实例:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在运行时,我们所知道的是模型的类型,例如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());
Run Code Online (Sandbox Code Playgroud)

但我不知道如何然后IModelBuilder<TModel>我可以调用实例,因此我可以调用并使用结果BuildModel().

Mar*_*ell 18

由于modelType只是一个Type实例,因此您无法自动执行此操作,因为没有非通用API可用.各种选择:

1:使用反射,例如(未经测试)

object builder = Activator.CreateInstance(...);
var model=builder.GetType().GetMethod("BuildModel").Invoke(builder,null);
Run Code Online (Sandbox Code Playgroud)

2:作弊dynamic:

dynamic builder = Activator.CreateInstance(...);
var model = builder.BuildModel();
Run Code Online (Sandbox Code Playgroud)

3:制作非通用版本IModelBuilder,并使用它

请注意,1和2依赖于接口的公共实现,并且对于(完全合法的)显式接口实现将失败.对于"1",您可以通过以下方式解决此问题:

var model = typeof(IModelBuilder<>).MakeGenericType(modelType)
       .GetMethod("BuildModel").Invoke(builder);
Run Code Online (Sandbox Code Playgroud)

最后一个偷偷摸摸的选择是从非泛型方法转换为泛型方法,因此在泛型方法中,您可以直接使用所有成员.有一种懒惰的方式来做到这一点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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 太好了!非常鬼鬼祟祟:) (2认同)
  • 使用动态感觉很脏,就像我在用PHP或其他东西编程一样。 (2认同)