英文:
Why can't I look up a specific generic method by its parameter types?
问题
System.Linq.Queryable
类型有一个名为 Contains
的方法,它有两个重载:
bool Contains<TSource>(this IQueryable<TSource>, TSource)
bool Contains<TSource>(this IQueryable<TSource>, TSource, IEqualityComparer<TSource>?)
我想获取第一个重载,所以我使用了以下代码:
var queryableContainsMethod = typeof(Queryable).GetMethod(
nameof(Queryable.Contains),
new[] { typeof(IQueryable<T>), typeof(T), });
但是这返回了 null
。为什么?
英文:
The System.Linq.Queryable
type has a method named Contains
with two overloads:
bool Contains<TSource>(this IQueryable<TSource>, TSource)
bool Contains<TSource>(this IQueryable<TSource>, TSource, IEqualityComparer<TSource>?)
I want to get the first overload, so I use the following code:
var queryableContainsMethod = typeof(Queryable).GetMethod(
nameof(Queryable.Contains),
new[] { typeof(IQueryable<T>), typeof(T), });
But this returns null
. Why?
NOTE: I am not asking how to get a reference to this method; I am asking why the code that I expect to give me said reference, does not.
答案1
得分: 3
以下是翻译好的内容:
-
The reason is that the parameters are generic while
IQueryable<T>
is not, for reflection purposes. It uses theT
type of the enclosing method.- 原因是参数是泛型的,而
IQueryable<T>
不是,用于反射目的。它使用封闭方法的T
类型。
- 原因是参数是泛型的,而
-
Unlike what I assumed, there's no need to specify
Static
in the binding flags.- 与我所假设的不同,不需要在绑定标志中指定
Static
。
- 与我所假设的不同,不需要在绑定标志中指定
-
It's possible to use
typeof
on a generic type by omitting the type parameters, egtypeof(IQueryable<>)
- 可以通过省略类型参数来在泛型类型上使用
typeof
,例如typeof(IQueryable<>)
- 可以通过省略类型参数来在泛型类型上使用
-
Borrowing from this similar question about OrderBy, the following snippet can retrieve the
Contains(TSource)
overload:- 借鉴自这个关于OrderBy的类似问题,以下代码片段可以检索
Contains(TSource)
重载:
- 借鉴自这个关于OrderBy的类似问题,以下代码片段可以检索
var TSource = Type.MakeGenericMethodParameter(0);
var method = typeof(Queryable).GetMethod(
nameof(Queryable.Contains),
new[] {
typeof(IQueryable<>).MakeGenericType(TSource),
TSource
}
);
- To get the second, we need to specify the
IEqualityComparer<>
parameter too:- 要获取第二个,我们还需要指定
IEqualityComparer<>
参数:
- 要获取第二个,我们还需要指定
var TSource = Type.MakeGenericMethodParameter(0);
var method = typeof(Queryable).GetMethod(
nameof(Queryable.Contains),
new[] {
typeof(IQueryable<>).MakeGenericType(TSource),
TSource,
typeof(IEqualityComparer<>).MakeGenericType(TSource)
}
);
英文:
The reason is that the parameters are generic while IQueryable<T>
is not, for reflection purposes. It uses the T
type of the enclosing method.
Unlike what I assumed, there's no need to specify Static
in the binding flags.
It's possible to use typeof
on a generic type by omitting the type parameters, eg typeof(IQueryable<>)
Borrowing from this similar question about OrderBy, the following snippet can retrieve the Contains(TSource)
overload:
var TSource = Type.MakeGenericMethodParameter(0);
var method=typeof(Queryable).GetMethod(
nameof(Queryable.Contains),
new[] {
typeof(IQueryable<>).MakeGenericType(TSource),
TSource
}
);
To get the second, we need to specify the IEqualityComparer<>
parameter too:
var TSource = Type.MakeGenericMethodParameter(0);
var method=typeof(Queryable).GetMethod(
nameof(Queryable.Contains),
new[] {
typeof(IQueryable<>).MakeGenericType(TSource),
TSource,
typeof(IEqualityComparer<>).MakeGenericType(TSource)
}
);
答案2
得分: 2
我的猜测是这是由于泛型类型参数造成的。
T
将在运行时解析为特定类型。因此,如果 T
是 int
,它将寻找具有签名 Contains<int>(this IQueryable<int>, int)
的方法。但是并不存在这样的方法。相反,您需要寻找一个泛型方法,而不指定泛型方法参数类型的实际类型。
我不确定您应该如何编写它,但是使用泛型类型的反射通常比常规反射更复杂。有许多反射方法,比如 MakeGenericMethod,可以帮助将开放泛型类型转换为具有指定泛型参数的类型,反之亦然。
正如一些评论者所指出的,可能还需要指定绑定标志,但我认为您还需要以其他方式处理泛型类型。
英文:
My guess is that it is due to the generic type argument.
T
will resolve to a specific type at runtime. So if T
is an int
it will look for a method with the signature Contains<int>(this IQueryable<int>, int)
. But no such method exists. You instead need to look for a generic method, without specifying the actual type of the generic method parameter type.
I'm not sure exactly how you should write that, but reflection with generic types tend to be even more complicated than regular reflection. There are a bunch of of reflection methods, like MakeGenericMethod to help convert from or to an open generic type and a type with the generic parameters specified.
As various commenters have noted, specifying binding flags might also be needed, but I would think you also need handle the generic types some other way.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论