如何使用Reflection创建通用对象

时间:2012-08-28 22:40:41

标签: c# generics reflection .net-4.5

首先让我说,我想要做的是获取泛型类中属性的值,该属性可以由继承自它的类覆盖。在基类中将其视为默认值,类的继承者可以覆盖它以设置自己的默认值。

我尝试使用System.Reflection.FieldInfo.GetValue直接在类型上使用反射,但这对于具有泛型类型的类不起作用。所以我认为我需要实例化该类才能看到值是什么。

我通过读取bin中的Dll并使用Reflection查找从我的界面继承的类型来检索“类型”。

我正在使用.NET 4.5

这里的文档似乎正好解释了我需要做什么 http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx

在本文档中,我可以看到的唯一区别是我们如何获得类型,我在bin中查找类型,他们只是调用typeof(),因为类型非常复杂,看起来这可能是错误匹配但是我看不出有什么遗失(如果有的话)

foreach (var item in types)
{
    var ts = item.GetField("DefaultTimeToExpire");
    Type[] typeArguments = item.GetGenericArguments();
    if (ts != null)
    {
        var t = item.MakeGenericType(typeArguments);
        var obj = Activator.CreateInstance(t);
        var timespan = obj.DefaultTimeToExpire;
        subscriberInfos.Add(new Tuple<string, Type, TimeSpan>(item.Name, item, timespan));
    }
}

我正在调用GetField来查找具有字段“DefaultTimeToExpire”的项目到目前为止,这部分可以很好地找到我需要的类型。 接下来,我调用GetGenericArguments,它返回Arguments类型的预期数组。 然后我调用MakeGenericType 最后创建实例,它给了我错误信息

“无法创建BusinessLogic.TestSubscriberXXX`1 [Message]的实例,因为Type.ContainsGenericParameters为true。”

这看起来就像我应该做的那样。 感谢

1 个答案:

答案 0 :(得分:4)

为了实例化泛型类型,您需要知道应该替换其类型参数的实际值(类型)。 GetGenericArguments()方法是一种反射形式,它只为您提供参数类型,而不是它们的实际值。这些价值取决于你......这是仿制药的全部要点。

如果item类型为List<T>,则item.GetGenericArguments()将返回一个数组,其中包含表示类型参数T的假“type”(其IsGenericParameter } property设置为true)。因此,将该参数类型传递回item.MakeGenericType()将只创建另一个与原始类型等效的开放泛型类型。要关闭泛型类型以便可以实例化,您需要提供实际(非参数)类型参数,例如int

例如,typeof(List<>).MakeGenericType(typeof(int))将返回typeof(List<int>),而typeof(List<>).MakeGenericType(typeof(List<>).GetGenericArguments())将仅返回typeof(List<>)。这就是你的代码中发生的事情。

如果有点不透明,我很抱歉,我不知道如何解释它。最重要的是,类似List<T>的类型只有在您想要替换T的类型时才有用。