获取方法的MethodInfo - 该操作仅适用于泛型类型。

5

我有以下两个Entity Framework的Include方法:

public static IIncludableQueryable<TEntity, TProperty> Include<TEntity, TProperty>(
    [NotNullAttribute] this IQueryable<TEntity> source, 
    [NotNullAttribute] Expression<Func<TEntity, TProperty>> navigationPropertyPath) 
    where TEntity : class;

public static IQueryable<TEntity> Include<TEntity>(
    [NotNullAttribute] this IQueryable<TEntity> source,
    [NotNullAttribute][NotParameterized] string navigationPropertyPath) 
    where TEntity : class;

我需要获取两个方法的MethodInfo。对于第一个方法,我使用了以下代码:

  MethodInfo include1 = typeof(EntityFrameworkQueryableExtensions)
    .GetMethods().First(x => x.Name == "Include" && x.GetParameters()
    .Select(y => y.ParameterType.GetGenericTypeDefinition())
    .SequenceEqual(new[] { typeof(IQueryable<>), typeof(Expression<>) }));

这个可以正常工作,但是当我尝试使用以下方法获取第二个时:
  MethodInfo include2 = typeof(EntityFrameworkQueryableExtensions)
    .GetMethods().First(x => x.Name == "Include" && x.GetParameters()
    .Select(y => y.ParameterType.GetGenericTypeDefinition())
    .SequenceEqual(new[] { typeof(IQueryable<>), typeof(String) }));

我遇到了以下错误:

此操作仅适用于泛型类型

我缺少了什么吗?


string navigationPropertyPath 是泛型吗? - CodeCaster
不,这只是一个字符串...我在顶部添加了方法签名。 - Miguel Moura
ParameterType.GetGenericTypeDefinition() 如何返回 typeof(String) - Lasse V. Karlsen
@haim770 ... Include 方法不在 QueryableExtensions 中。 - Miguel Moura
@CodeCaster 在我的问题开头,我添加了2个Include方法。我需要获取两者的MethodInfo,以便稍后使用一个值。例如,对于include1,我将使用:(IQueryable<T>)include1.MakeGenericMethod(typeof(T), typeof(String)).Invoke(null, new Object[] { source, navigationSourcePath }); - Miguel Moura
显示剩余6条评论
1个回答

6
好的,让我们来分解一下。首先,您需要获取该方法的所有重载:
var overloads = typeof(EntityFrameworkQueryableExtensions)
    .GetMethods()
    .Where(method => method.Name == "Include");

然后,您需要将参数类型与特定序列匹配,以便选择适当的重载。您代码的问题在于假设所有参数都是通用类型,这并不是事实。您可以使用三元运算符来区分通用和非通用参数类型:

var include2 =  overloads.Where(method => method
    .GetParameters()
    .Select(param => param.ParameterType.IsGenericType ? param.ParameterType.GetGenericTypeDefinition() : param.ParameterType)
    .SequenceEqual(new[] { typeof(IQueryable<>), typeof(string) }));

这将产生第二个重载,如预期的那样,并且不会抱怨您尝试从第二个参数调用GetGenericTypeDefinitiontypeof(string)上。

首先,我认为你指的是IsGenericParameter而不是IsGenericType。其次,你返回的不是MethodInfos而是Types。所以include2是一个Types列表。最后,我得到了没有任何项目的结果。有什么想法为什么会这样? - Miguel Moura
1
@MiguelMoura 不,我的意思是 IsGenericType 而不是 IsGenericParameter。我亲自测试过了,它可以工作,见:https://gist.github.com/masaeedu/7150ee92becdad4e514dfa160da460ad。其次,我在两个片段中都返回了 IEnumerable<MethodInfo>,而不是 IEnumerable<Type>。我鼓励你将代码原样粘贴到你的 IDE 中。 - Asad Saeeduddin
你使用的是哪个版本的C#?我正在使用.NET Core。我完全复制你的代码后,出现了错误:“Type”不包含“IsGenericType”的定义,也没有接受类型为“Type”的第一个参数的扩展方法“IsGenericType”(是否缺少使用指令或程序集引用?)。 - Miguel Moura
@MiguelMoura 我正在使用完整的框架。在 .NET Core BCL 中,反射已经发生了变化(例如,你需要使用 GetTypeInfo),因此如果你正在使用 Core,你需要在标签中提到这种事情。无论如何,在 Core 中可能有一个等效的 IsGenericType,我需要去搜索一下。 - Asad Saeeduddin
它与param.ParameterType.IsConstructedGenericType一起工作... 不确定它是否等效。 - Miguel Moura
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接