Question

I have a number of MethodBase instances referencing different open generic methods (expected), e.g. representing the following methods:

T Foo<T>(T nevermind, T other);
T Foo<T>(string nevermind, T other);

And I have a single MethodBase instance referencing closed method that was actually called (actual), e.g.:

int Foo<int>(string nevermind, int other);

How can I programatically check if actual closed method could match any of given expected open methods, especially when considering all the generics pitfalls and complications?

Specifically, I would like to identify that the correct item from expected list for given actual closed method is T Foo<T>(string nevermind, T other); and not the second one.

Moreover, for MethodBase corresponding to double Foo<double>(double something, string other) I'd like to have no results matched.

Is iterating through candidate methods and checking if each parameter from expected is assignable from corresponding actual parameter a good way? If so, is it the simplest way? Do I need to consider any special cases to not match methods that will not be chosen according to method overloads resolution rules in .NET?

Was it helpful?

Solution

Tl;dr. The problem is not possible to solve using reflection, at least as I understand it, and without more specificity..

Method resolution rules are extremely complicated, especially for generic methods. There are many pitfalls you will fall into. You will need to know not only the method, the type parameter, but also a lot of information about the target, along with its own type parameters. In some cases, where the method was called from.

  • Method has implementation in a base class but is hidden by the child.
  • Method is from an interface, and was implemented explicitly, and may have another method with the same name on the implementer.
  • A methods such as Foo<T>(T a, string other), Foo<T>(string a, T other), Foo<T>(string a, string other) and some other variations cannot be disambiguated for T = string unless you know where the call is coming from (these are legal methods, and the one that gets called depends on several things).
  • Generic constraints can be placed on methods.
  • Polymorphism on the argument types, including generic variance for interfaces and delegates.
  • Optional parameters.
  • This goes on and on.

Basically, it can never work. Not using reflection. Not the way you're proposing. Even if you have restrictions about what calls can be made, you'd have to decide which things to check and which not, and you will always miss a few. These aren't the only pitfalls by the way, just a random sampling.

However, you do have some options.

The first, and best option in my opinion, is going a step back and thinking about the original problem. Post that if you can. It might have a different answer, and people will be able to advise you better. Hopefully it's less complicated to understand.

If you limited the scope of the matter greatly, such as no generic constraints, no interfaces, and so forth, this might be possible. It would be error prone, because there are lots of gotcha's.

You can try resolving it at runtime using dynamic binding, but the way dynamic binding resolves methods may be different from the way it normally happens. I don't know much about this, though.

You can hook the runtime and also investigate method calls as they are resolved. There are libraries for this. This will even allow you to understand how late binding is resolved.

Finally, you can look into the IL, possibly with the aid of various tools and libraries such as Mono.Cecil. In the built library, method resolution has already been performed, so you will see exactly which methods are called from which locations. This doesn't sound feasible however.

Oh, there is Roslyn, and other compilers with interfaces. They already have the resolution logic implemented, so they may make the task easier. IF they are open source, you can try to understand how method resolution is performed there. I'm kind of out of my depth here, though. And I suspect it's not feasible.

I don't like posting links to specific libraries because I'd rather you just research them. Also because there are many options.

To summarize, at least in my opinion, and as I understand the problem, without great restrictions on the methods and more information, it is impossible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top