C# 方法只能对Type.IsGenericParameter为true的类型调用

C# 方法只能对Type.IsGenericParameter为true的类型调用,c#,reflection,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

我在一个例程中遇到这个错误,该例程使用反射来转储一些对象属性,类似下面的代码

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的类型调用方法”

在此阶段,调试器中的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为true的类型”到底是什么,更重要的是 如果不尝试/捕获,如何避免此错误

那么,“Type.IsGenericParameter为true的类型”到底是什么

这意味着它是一个开放泛型类型中的泛型类型参数,也就是说,我们还没有选择一个
t
;例如:

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

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

所以,;你有一些开放的泛型吗?如果你能举一个例子,说明你的
对象是从哪里来的?

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

在发生故障时,循环已到达调用的
Type
class属性。但是,
type
类的这个实例所描述的类型是
System.Data.SqlClient.SqlConnection
,它不是方法的泛型类型

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

关键是您正在检查类的类型
type
。这有点循环,但请想想:-

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

类ouch描述的是什么?

我如何避免这个错误而不尝试/捕获?

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

这些额外成员来自哪里?

您的
obj
已经包含表示
SqlConnection
RuntimeType
对象,而不是
SqlConnection
的实例
obj.GetMembers()
将返回
SqlConnection
类的65个成员,但是通过再次调用
GetType()
,可以获得
RuntimeType
的188个成员

什么是
IsGenericParameter


您可以使用表示类或方法的泛型参数的
RuntimeType
实例,而不是表示类(在
List.ConvertAll
中的
T
TOutput
。在这种情况下,表示
TOutput
的对象上的
DeclaringMethod
可以让您得到一个表示
ConvertAll
方法的
MethodInfo>对象。但是,当
RuntimeType
表示一个类时,declaring方法没有意义。这就是为什么读取属性会导致您看到的异常。

首先,您做出了一个错误的假设,即,您假设
成员
返回了
系统.Data.SqlClient.SqlConnection
实例的成员,但它没有返回。返回的是成员属于
系统的实例。键入

从MSDN文档中获取:

获取
DeclaringMethod
属性 在其
IsGenericParameter
属性为false抛出一个
无效操作异常


所以…抛出一个
InvalidOperationException
是可以理解的,因为很自然,这里没有处理一个打开的泛型类型。有关打开的泛型类型的解释,请参阅。

我的问题是通过删除模型中的重复字段和表,并在model.edm中注释定义查询和删除存储:来解决的x XML文件。

OP确实在其System.RuntimeType中声明了obj的类型。从我所看到的,问题不在于是否存在开放泛型,而是是否存在正常类型:)我从一个异常开始(在本例中是SqlException)它被传递到我的转储例程。转储例程是递归的,因此对异常中的所有属性和字段调用转储。我的代码中有一些泛型,但没有打开的泛型。让我困惑的是,错误似乎表明p.GetValue仅在GenericParameter为true时才起作用,而GenericParameter显然不是true。@sgmoore:y怎么办GetValue正在做什么?它调用obj上PropertyInfo描述的属性的get操作。PropertyInfo描述类型对象的DeclaringMethod,因此GetValue调用DeclaringMethod的get操作,该操作随后失败,因为obj不是方法的泛型类型。@anthonywjones。我(现在)理解这一点.事后看来,这似乎很明显,但直到我读到埃里克·史密斯的答案后,它才点击。我唯一的借口是错误消息中的单词“方法”把我甩了。(是的,我知道属性实际上是一个get-And-set方法,但我不认为属性是方法,并且假设它所说的方法一定是GetValue方法)我想我开始明白了。它