2

This may sound stupid but I cannot get the MethodInfo of Queryable.Join(...). I want to get it because of How to use a Type variable in a generic method call (C#)

It has 2 available method signatures and I want to get the one without IEqualityComparer, so I need to specify Type[] in GetMethod.

I wrote something like

MethodInfo joinMethod = typeof( Queryable ).GetMethod( "Join", new Type[] { typeof(IEnumerable<>), typeof(Expression<Func<>>), typeof(Expression<Func<>>), typeof(Expression<Func<>>)});

but it doesn't work. I'm unable to specify the types in generics above, because they are passed as Type from outside (and this is why I need this reflection).

Can anyone tell me how? Thanks!

Community
  • 1
  • 1
uni
  • 613
  • 1
  • 7
  • 11
  • 1
    Remember that `Queryable.Join` is an extension method so the first parameter of the method is `this IQueryable`. Additionally, [this](http://stackoverflow.com/questions/269578/get-a-generic-method-without-using-getmethods) question is very similar. – vcsjones Oct 14 '11 at 16:02

2 Answers2

5

Working with generics and reflection can be a bit tedious. Your best bet (to keep things simple) is to use GetMethods and filter by what you are looking for.

//Overly simplified
MethodInfo joinMethod = typeof(Queryable)
            .GetMethods(BindingFlags.Static | BindingFlags.Public)
            .Where(m => m.Name == "Join" && m.GetParameters().Length == 5)
            .First();

Given that, the MethodInfo is not invokable at this point. You need to make a generic version of it by using joinMethod.MakeGenericMethod(/*type array*/). In your case, you would need to use 4 types: TOuter, TInner, TKey, TResult.

var genericJoinMethod = joinMethod.MakeGenericMethod(new Type[]{your types here});

Now you can use genericJoinMethod as you'd expect to.

As far as I know, that is the only way to do it if you don't know the types at compile-time.

EDIT:

Given your comment, I think it should look something like this:

MethodInfo joinMethod = typeof(Queryable)
            .GetMethods(BindingFlags.Static | BindingFlags.Public)
            .Where(m => m.Name == "Join" && m.GetParameters().Length == 5)
            .First();
var genericJoinMethod = joinMethod.MakeGenericMethod(typeof(TType), typeof(TType), JoinKeyType, typeof(TType));
result = genericJoinMethod.Invoke( result, new object[] { result, items, OuterKeySelector, InnerKeySelector, ResultSelector } );
vcsjones
  • 138,677
  • 31
  • 291
  • 286
  • That really simplifies things! I got another error when trying to invoke the method after making generic method like this `joinMethod.MakeGenericMethod( typeof( TType ), typeof( TType ), JoinKeyType, typeof( TType ) ); result = joinMethod.Invoke( result, new object[] { result, items, OuterKeySelector, InnerKeySelector, ResultSelector } );` The error is "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true".. Any ideas? – uni Oct 14 '11 at 16:21
  • 2
    @uni - Make sure you use the new `MethodInfo` that `MakeGenericMethod` returns when calling `Invoke`. – vcsjones Oct 14 '11 at 16:28
  • I'm wondering if somewhere in the DLR there isn't all of this already, the C# part must have something to resolve the `MethodInfo` from call in a specific call site. But it might not be exposed :( – Julien Roncaglia Oct 14 '11 at 16:41
1

Before you start to implement some complicated reflection search with strings and parameter counts involved, why don't you step back, and let the compiler do what he is better at?

var fakeExp = (Expression<Func<IQueryable<int>>>)(() => new int[0].AsQueryable().Join(new int[0], x => x, x => x, (x, y) => x));
return ((MethodCallExpression)fakeExp.Body).Method.GetGenericMethodDefinition();

Obviously you can put whatever you want in your expression, as long as the top level stuff is your Join method call. Types do not matter neither.

MBoros
  • 1,090
  • 7
  • 19