如何获取 Enumerable.SequenceEqual 的 MethodInfo
How to get the MethodInfo for Enumerable.SequenceEqual
我正在尝试使用 Type.GetMethod(...)
获取 Enumerable.SequenceEqual
的 MethodInfo
。到目前为止,我已经尝试了以下方法:
var mi = typeof(Enumerable).GetMethod(nameof(Enumerable.SequenceEqual),
BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any,
new Type[] { typeof(IEnumerable<>), typeof(IEnumerable<>) }, null);
和
var enumTyped = typeof(IEnumerable<>).MakeGenericType(ValueType);
var mi = typeof(Enumerable).GetMethod(nameof(Enumerable.SequenceEqual),
BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any,
new Type[] { enumTyped, enumTyped }, null);
但是,这两种解决方案return null
而不是我想要的方法。我知道可以通过调用 GetMethods()
和过滤来检索该方法,但我非常想知道如何使用 GetMethod(...)
.
检索它
不幸的是,为了使用 Type.GetMethod(string name, Type[] types)
获得通用泛型方法,您必须在 Type[]
中为方法提供正确的泛型类型,这意味着当您尝试这样做时:
Type requiredType = typeof(IEnumerable<>);
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { requiredType, requiredType });
你实际上需要做这样的事情:
Type requiredType = typeof(IEnumerable<TSource>);
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { requiredType, requiredType });
因为如果您查看 SequenceEqual
的签名,泛型类型是 IEnumerable<TSource>
而不是 IEnumerable<>
。
public static IEnumerable<TSource> SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
但是: 您无权访问类型 TSource
以便使用它。
所以获得 IEnumerable<TSource>
的唯一方法是像下面这样使用反射:
MethodInfo info = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(x => x.Name.Contains("SequenceEqual"))
.Single(x => x.GetParameters().Length == 2);
Type genericType = typeof(IEnumerable<>).MakeGenericType(infos.GetGenericArguments());
而不是使用
获取方法
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { genericType, genericType });
但这要求我们无论如何都要获取 SequenceEqual
方法,所以令人遗憾的是,当使用 [=23 的重载很少时,让该方法成为通用方法=] 而不是 GetMethods
实际上是不可能的* (你 CAN 实现一个 Binder
并在 GetMethod
方法中使用它,但它需要很长的编码,这可能会出现错误且无法维护,应该避免).
想对以前的答案进行一些补充。首先,确实不可能使用单个 GetMethod 来做你想做的事。但是,如果您不想调用 GetMethods 并获取 Enumerable 的所有 180 多个方法,您可以这样做:
var mi = typeof(Enumerable).GetMember(nameof(Enumerable.SequenceEqual), MemberTypes.Method,
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod).OfType<MethodInfo>().ToArray();
GetMember 调用将 return 您只需 2 个 SequenceEqual 方法重载,您可以选择其中一个并执行 MakeGenericMethod,如其他答案中所示。
此外,根据您的目标,您可以考虑使用表达式:
var source = Expression.Parameter(
typeof(IEnumerable<string>), "source");
var target = Expression.Parameter(
typeof(IEnumerable<string>), "target");
var callExp = Expression.Call(typeof(Enumerable), "SequenceEqual", new Type[] { typeof(string)},
source, target);
var lambda = Expression.Lambda<Func<IEnumerable<string>, IEnumerable<string>, bool>>(callExp, source, target).Compile();
var result = lambda(new[] { "1", "2", "3" }, new[] { "1", "2", "3" });
Debug.Assert(result);
另一个基于之前两个答案的答案略有不同,但使用了 MakeGenericMethod 调用和 VisualBasic 版本。
Dim lSequanceEqual As MethodInfo = GetType(System.Linq.Enumerable).GetMethods()
.First(Function(mi) mi.Name.Contains(NameOf(System.Linq.Enumerable.SequenceEqual)) AndAlso mi.GetParameters.Length = 2)
Dim lMethod As MethodInfo = lSequanceEqual.MakeGenericMethod(New Type() { GetType(String)})
if CBool(lMethod.Invoke(Nothing, New Object() { firstList, secondList})) Then 'Do something
我正在尝试使用 Type.GetMethod(...)
获取 Enumerable.SequenceEqual
的 MethodInfo
。到目前为止,我已经尝试了以下方法:
var mi = typeof(Enumerable).GetMethod(nameof(Enumerable.SequenceEqual),
BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any,
new Type[] { typeof(IEnumerable<>), typeof(IEnumerable<>) }, null);
和
var enumTyped = typeof(IEnumerable<>).MakeGenericType(ValueType);
var mi = typeof(Enumerable).GetMethod(nameof(Enumerable.SequenceEqual),
BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any,
new Type[] { enumTyped, enumTyped }, null);
但是,这两种解决方案return null
而不是我想要的方法。我知道可以通过调用 GetMethods()
和过滤来检索该方法,但我非常想知道如何使用 GetMethod(...)
.
不幸的是,为了使用 Type.GetMethod(string name, Type[] types)
获得通用泛型方法,您必须在 Type[]
中为方法提供正确的泛型类型,这意味着当您尝试这样做时:
Type requiredType = typeof(IEnumerable<>);
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { requiredType, requiredType });
你实际上需要做这样的事情:
Type requiredType = typeof(IEnumerable<TSource>);
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { requiredType, requiredType });
因为如果您查看 SequenceEqual
的签名,泛型类型是 IEnumerable<TSource>
而不是 IEnumerable<>
。
public static IEnumerable<TSource> SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
但是: 您无权访问类型 TSource
以便使用它。
所以获得 IEnumerable<TSource>
的唯一方法是像下面这样使用反射:
MethodInfo info = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(x => x.Name.Contains("SequenceEqual"))
.Single(x => x.GetParameters().Length == 2);
Type genericType = typeof(IEnumerable<>).MakeGenericType(infos.GetGenericArguments());
而不是使用
获取方法typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { genericType, genericType });
但这要求我们无论如何都要获取 SequenceEqual
方法,所以令人遗憾的是,当使用 [=23 的重载很少时,让该方法成为通用方法=] 而不是 GetMethods
实际上是不可能的* (你 CAN 实现一个 Binder
并在 GetMethod
方法中使用它,但它需要很长的编码,这可能会出现错误且无法维护,应该避免).
想对以前的答案进行一些补充。首先,确实不可能使用单个 GetMethod 来做你想做的事。但是,如果您不想调用 GetMethods 并获取 Enumerable 的所有 180 多个方法,您可以这样做:
var mi = typeof(Enumerable).GetMember(nameof(Enumerable.SequenceEqual), MemberTypes.Method,
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod).OfType<MethodInfo>().ToArray();
GetMember 调用将 return 您只需 2 个 SequenceEqual 方法重载,您可以选择其中一个并执行 MakeGenericMethod,如其他答案中所示。 此外,根据您的目标,您可以考虑使用表达式:
var source = Expression.Parameter(
typeof(IEnumerable<string>), "source");
var target = Expression.Parameter(
typeof(IEnumerable<string>), "target");
var callExp = Expression.Call(typeof(Enumerable), "SequenceEqual", new Type[] { typeof(string)},
source, target);
var lambda = Expression.Lambda<Func<IEnumerable<string>, IEnumerable<string>, bool>>(callExp, source, target).Compile();
var result = lambda(new[] { "1", "2", "3" }, new[] { "1", "2", "3" });
Debug.Assert(result);
另一个基于之前两个答案的答案略有不同,但使用了 MakeGenericMethod 调用和 VisualBasic 版本。
Dim lSequanceEqual As MethodInfo = GetType(System.Linq.Enumerable).GetMethods()
.First(Function(mi) mi.Name.Contains(NameOf(System.Linq.Enumerable.SequenceEqual)) AndAlso mi.GetParameters.Length = 2)
Dim lMethod As MethodInfo = lSequanceEqual.MakeGenericMethod(New Type() { GetType(String)})
if CBool(lMethod.Invoke(Nothing, New Object() { firstList, secondList})) Then 'Do something