[英]Casting generic type instances created 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
。 我可以找到相關模型構建器的實例,如下所示:
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()
的結果。
由於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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.