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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1346238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:27:16  来源:igfitidea点击:

Method may only be called on a Type for which Type.IsGenericParameter is true

c#reflection

提问by sgmoore

I am getting this error on a routine which uses reflection to dump some object properties, something like the code below.

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

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);

       ...
    }
}

The actual error is "Exception has been thrown by the target of an invocation" with an inner exception of "Method may only be called on a Type for which Type.IsGenericParameter is true."

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

At this stage in the debugger obj appears as

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

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

with the type System.RuntimeType

类型为 System.RuntimeType

The method m is {System.Reflection.MethodBase DeclaringMethod}

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

Note that obj is of type System.RuntimeType and members contains 188 items whereas a simple typeof(System.Data.SqlClient.SqlConnection).GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance) only returns 65.

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

I tried checking isGenericParameter on both obj and p.PropertyType, but this seems to be false for most properties including those where p.GetValue works.

我尝试在 obj 和 p.PropertyType 上检查 isGenericParameter,但这对于大多数属性(包括 p.GetValue 起作用的属性)来说似乎是错误的。

So what exactly is a "Type for which Type.IsGenericParameter is true" and more importantly how do I avoid this error without a try/catch?

那么究竟什么是“Type.IsGenericParameter 为真的类型”,更重要的是如何在没有 try/catch 的情况下避免此错误?

采纳答案by Eric Smith

Firstly, you've made in incorrect assumption, that is, you've assumed that membershas returned the members of an instance of System.Data.SqlClient.SqlConnection, which it has not. What has been returned are the members of an instance of System.Type.

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

From the MSDN documentation for DeclaringType:

DeclaringType的 MSDN 文档中:

Getting the DeclaringMethodproperty on a type whose IsGenericParameterproperty is false throws an InvalidOperationException.

获取 属性为 falseDeclaringMethod的类型的 IsGenericParameter属性会引发 InvalidOperationException.

So... it's understandable that an InvalidOperationExceptionis being thrown, since naturally, you're not dealing with an open generic type here. See Marc Gravells answerfor an explanation of open generic types.

所以……InvalidOperationException抛出an是可以理解的,因为很自然地,您在这里处理的不是开放的泛型类型。有关开放泛型类型的解释,请参阅Marc Gravells 的回答

回答by Marc Gravell

So what exactly is a "Type for which Type.IsGenericParameter is true"

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

That means it is a generic type argument in an open generic type - i.e. where we haven't picked a Tyet; for example:

这意味着它是开放泛型类型中的泛型类型参数——即我们还没有选择 a 的地方T;例如:

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

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

So; have you got some open generics hanging around? Perhaps if you can give an example of where you got your objfrom?

所以; 你有一些开放的泛型吗?也许你能举个例子说明你从哪里来的obj

回答by AnthonyWJones

All the clues are in there. The type of the obj is the Typeclass itself (or rather the strange RuntimeType derivative).

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

At the point of failure you loop has arrived the Typeclass property called DeclaringMethod. However the type that this instance of the Typeclass is describing is System.Data.SqlClient.SqlConnectionwhich is not a Generic Type of a method.

在您循环的失败点到达了Type名为DeclaringMethod. 然而,这个Type类的实例所描述的System.Data.SqlClient.SqlConnection类型不是方法的通用类型。

Hence attempting to invoke the get on DeclaringMethod results in the exception.

因此,尝试在 DeclaringMethod 上调用 get 会导致异常。

The key is you are examining the type of the class Type. Its a bit circular but think of this:-

关键是您正在检查类的类型Type。它有点圆,但想想这个:-

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

What is class ouch describing?

class ouch 描述的是什么?

回答by stevemegson

How do I avoid this error without a try/catch?

如何在没有 try/catch 的情况下避免此错误?

You almost certainly can't. When you call p.GetValue, you're calling the getter on that property, which could throw any kind of exception. For example, SqlConnection.ServerVersion will throw an exception if the connection is closed, and you have to handle that.

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

Where are these extra members coming from?

这些额外的成员来自哪里?

Your objalready contains the RuntimeTypeobject representing SqlConnection, rather than an instance of SqlConnection. obj.GetMembers()would return the 65 members of the SqlConnectionclass, but by calling GetType()again, you get the 188 members of RuntimeType.

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

What is IsGenericParameter?

什么是IsGenericParameter

Instead of representing a class, you can have an instance of RuntimeTypethat represents a generic parameter to a class or method (The Tand TOutputin List<T>.ConvertAll<TOutput>. In this case, DeclaringMethodon the object representing TOutputwould let you get a MethodInfoobject representing the ConvertAll<>method. However, when the RuntimeTyperepresents a class, the idea of a declaring method makes no sense. That's why reading the property causes the exception that you saw.

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

回答by aseman arabsorkhi

My problem was solved by deleting repetitive fields and tables in my model and commented defining query and deleted store: in Model.edmx XML File.

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