只能在Type.IsGenericParameter为true的Type上调用方法

时间:2009-08-28 10:42:24

标签: c# reflection

我在使用反射转储一些对象属性的例程上遇到此错误,类似于下面的代码。

MemberInfo[] members = obj.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance) ;

foreach (MemberInfo m in members)
{
    PropertyInfo p = m as PropertyInfo;
    if (p != null)
    {
       object po = p.GetValue(obj, null);

       ...
    }
}

实际错误是“调用目标已抛出异常” 内部异常“只能在Type.IsGenericParameter为true的Type上调用Method。”

在调试器的这个阶段,obj显示为

  {Name = "SqlConnection" FullName = "System.Data.SqlClient.SqlConnection"} 

,类型为System.RuntimeType

方法m是{System.Reflection.MethodBase DeclaringMethod}

请注意,obj的类型为System.RuntimeType,成员包含188个项目,而简单 typeof(System.Data.SqlClient.SqlConnection).GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)仅返回65.

我尝试在obj和p.PropertyType上检查isGenericParameter,但对于大多数属性,包括那些p.GetValue工作的属性,这似乎都是错误的。

那究竟什么是“Type.IsGenericParameter为真的类型”,更重要的是 如果没有try / catch,我该如何避免这个错误?

5 个答案:

答案 0 :(得分:14)

  

那究竟什么是“Type.IsGenericParameter为真的类型”

这意味着它是开放泛型类型中的泛型类型参数 - 即我们尚未选择T的地方;例如:

// true
bool isGenParam = typeof(List<>).GetGenericArguments()[0].IsGenericParameter;

// false (T is System.Int32)
bool isGenParam = typeof(List<int>).GetGenericArguments()[0].IsGenericParameter;

因此;你有一些开放的仿制药吗?也许你可以举例说明你从obj获得的地方?

答案 1 :(得分:13)

首先,你做出了错误的假设,也就是说,你假设members已经返回System.Data.SqlClient.SqlConnection实例的成员,而它没有。返回的是System.Type实例的成员。

来自DeclaringType的MSDN文档:

  

获取DeclaringMethod属性   在IsGenericParameter的类型上   属性是假的   InvalidOperationException

所以......抛出InvalidOperationException是可以理解的,因为很自然,你不会在这里处理一个开放的泛型类型。有关开放泛型类型的说明,请参阅Marc Gravells answer

答案 2 :(得分:3)

所有的线索都在那里。 obj的类型是Type类本身(或者更确切地说是奇怪的RuntimeType派生类)。

在失败时,你的循环已经到达名为DeclaringMethodType类属性。但是,Type类的这个实例所描述的类型是System.Data.SqlClient.SqlConnection,它不是方法的泛型类型。

因此,尝试调用get on DeclaringMethod导致异常。

关键是你正在研究班级Type的类型。它有点循环但想到这个: -

SqlConnection s = new SqlConnection();
Type t = s.GetType()
Type ouch = t.GetType()

什么是类ouch描述?

答案 3 :(得分:1)

如果没有try / catch,我该如何避免此错误?

你几乎肯定不能。当你调用p.GetValue时,你正在调用该属性的getter,这可能会抛出任何异常。例如,如果连接关闭,SqlConnection.ServerVersion将抛出异常,您必须处理它。

这些额外成员来自哪里?

您的obj已包含代表RuntimeType的{​​{1}}对象,而不是SqlConnection的实例。 SqlConnection将返回obj.GetMembers()班级的65名成员,但再次致电SqlConnection,您将获得GetType()的188名成员。

什么是RuntimeType

您可以拥有IsGenericParameter的实例,而不是代表一个类,该实例代表类或方法的通用参数(RuntimeType中的TTOutput。在这种情况下,代表List<T>.ConvertAll<TOutput>的对象上的DeclaringMethod将允许您获得表示TOutput方法的MethodInfo对象。但是,当ConvertAll<>表示类时,声明方法的想法毫无意义。这就是为什么读取属性会导致你看到的异常。

答案 4 :(得分:1)

我的问题已解决,方法是删除模型中的重复字段和表,并注释定义查询并删除存储:Model.edmx XML文件中。