为什么无法通过参数类型查找特定的通用方法?

huangapple go评论73阅读模式
英文:

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

以下是翻译好的内容:

  1. 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.

    • 原因是参数是泛型的,而IQueryable<T>不是,用于反射目的。它使用封闭方法的T类型。
  2. Unlike what I assumed, there's no need to specify Static in the binding flags.

    • 与我所假设的不同,不需要在绑定标志中指定Static
  3. It's possible to use typeof on a generic type by omitting the type parameters, eg typeof(IQueryable<>)

    • 可以通过省略类型参数来在泛型类型上使用typeof,例如typeof(IQueryable<>)
  4. 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 
    }
);
  1. 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 将在运行时解析为特定类型。因此,如果 Tint,它将寻找具有签名 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.

huangapple
  • 本文由 发表于 2023年6月29日 18:22:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76580148.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定