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

sgm*_*ore 19 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);

       ...
    }
}
Run Code Online (Sandbox Code Playgroud)

实际错误是"调用目标抛出了异常",内部异常为"只能在Type.IsGenericParameter为true的Type上调用Method".

在调试器obj的这个阶段出现

  {Name = "SqlConnection" FullName = "System.Data.SqlClient.SqlConnection"} 
Run Code Online (Sandbox Code Playgroud)

使用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的情况下避免这个错误?

Mar*_*ell 15

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

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

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

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

所以; 你有一些开放的仿制药吗?也许你可以举一个例子说明你从哪里来的obj


Eri*_*ith 13

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

DeclaringType的MSDN文档:

DeclaringMethodIsGenericParameter 属性为false 的类型上 获取属性会引发属性 InvalidOperationException.

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

  • 我以为我开始看到光明.这并不是说p.GetValue只能"调用Type.IsGenericParameter为true的Type",而是p表示的底层属性,在本例中是DeclaringMethod,只能调用Type.IsGenericParameter是真正. (2认同)