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?
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.
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).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.