Miguel Moura Miguel Moura - 16 days ago 6
C# Question

Get MethodInfo of method - This operation is only valid on generic types

I have the following two Entity Framework's Include methods:

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;


I need to get the MethodInfo for both methods. For the first one I used:

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


This works but when I try to get the second one using the following:

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


I get the error:


This operation is only valid on generic types


What am I missing?

Answer

Okay, lets break this apart. First you want to get all overloads of the method:

var overloads = typeof(EntityFrameworkQueryableExtensions)
    .GetMethods()
    .Where(method => method.Name == "Include");

Then you want to match the parameter types against a particular sequence so you can select the appropriate overload. The problem with your code is that you're assuming all parameters are generic types, when this isn't the case. You can use a ternary clause to distinguish between generic and non-generic parameter types:

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

This produces the second overload, as expected, and doesn't complain about you trying to invoke GetGenericTypeDefinition on typeof(string) from the second parameter.