投射使用反射创建的泛型类型实例 [英] Casting generic type instances created using Reflection
问题描述
我正在使用反射创建泛型类型的实例:
I'm creating instances of a generic type using 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();
}
}
在运行时,我们所知道的只是模型的类型,例如 MyModel
.我可以找到相关模型构建器的实例,如下所示:
At runtime all we know is the Type of model e.g. MyModel
. I can find instances of the relevant model builder like so:
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()
的结果./p>
But I'm not sure how I can then cast the instance as IModelBuilder<TModel>
so I can call and work with the result of BuildModel()
.
推荐答案
由于 modelType
只是一个 Type
实例,由于存在没有可用的非通用API.各种选项:
Since modelType
is just a Type
instance, you can't do that automatically, since there is no non-generic API available. Various options:
1:例如,使用反射(未测试)
1: use reflection, for example (untested)
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
的非通用版本,并使用该版本
3: make a non-generic version of IModelBuilder
, and use that
请注意,1&2依赖于接口的公共实现,并且对于(完全合法的)显式接口实现将失败.对于"1",您可以通过以下方法解决此问题:
Note that 1 & 2 rely on a public implementation of the interface, and will fail for a (perfectly legal) explicit interface implementation. For "1", you can fix this via:
var model = typeof(IModelBuilder<>).MakeGenericType(modelType)
.GetMethod("BuildModel").Invoke(builder);
最后一个偷偷摸摸的选择是将非泛型方法转换为泛型方法,因此在泛型方法内部,您可以直接使用所有成员.有一种偷懒的方法可以通过 dynamic
:
A final sneaky option is to flip from a non-generic method into a generic method, so inside the generic method you can use all the members directly. There's a lazy way to do that via 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);
}
}
这篇关于投射使用反射创建的泛型类型实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!