Get collection of methods with the same name
Asked Answered
V

3

9

I've got some code (for helping with url routing) that tries to find an action method in a controller.

My controller looks like so:

public ActionResult Item(int id)
{
    MyViewModel model = new MyViewModel(id);
    return View(model);
}

[HttpPost]
public ActionResult Item(MyViewModel model)
{
    //do other stuff here
    return View(model);
}

The following code attempts to find a method matching the url action:

//cont is a System.Type object representing the controller
MethodInfo actionMethod = cont.GetMethod(action);

Today this code threw a System.Reflection.AmbiguousMatchException: Ambiguous match found which makes sense given my two methods have the same name.

I took a look at the available methods of the Type object and found public MethodInfo[] GetMethods(); which seems to do what I want, except there doesn't seem to be an overload for searching for a method with a specific name.

I could just use this method and search everything it returns, but I'm wondering if there's another (simpler) way to obtain a list of all methods in a class with a specific name, when there are multiple.

Vella answered 29/5, 2013 at 13:30 Comment(0)
M
5

There's nothing wrong with searching through the result of GetMethods really, but if you really wanted to, you could do:

var flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;

var myOverloads = typeof(MyClass)
                  .GetMember("OverloadedMethodName", MemberTypes.Method, flags)
                  .Cast<MethodInfo>();

...which uses this method. You may need to change the binding-flags as per your requirements.

I checked reference-source and found that this internally relies on a cached-multimap keyed by member-name (see RuntimeType.GetMemberList), so it should be somewhat more efficient than searching in client code each time.

You could also do (more convenient but slightly less efficient, in theory at least):

var myOverloads = typeof(MyClass).GetMember("OverloadedMethodName")
                                 .OfType<MethodInfo>();
Mix answered 29/5, 2013 at 13:38 Comment(6)
Trying it now. I am concerned about the efficiency since this code runs for every single request.Vella
If you are so concerned, why not memoize yourself? That's likely to be much more efficient since Reflection has to create a new array for you every time (it can't cache the array itself since you might mutate it and it doesn't trust you not to).Mix
It seems that the number of members of the type doesn't influence the speed of GetMember (or the impact is neglectable compared to GetMethods)!?!Regine
I hadn't gotten that far, though I may well end up doing that.Vella
By the way, are you looking to execute the method? If so (and you are really concerned by performance, backed by profiling), I suggest memoizing yourself and using Delegate.CreateDelegate.Mix
No, I don't need to actually execute it (not in my code anyway). All I do is modify the parameters of the route if the action is found.Vella
B
2

Just Get the Collection of Methods with GetMethods() amd filter them by using a Lambda Expression: GetMethods().Where(p => p.Name == "XYZ").ToList();

Behlke answered 29/5, 2013 at 13:33 Comment(2)
I did specifically mention I was hoping to not have to do this, but thanks nonetheless :)Vella
We had that topic yesterday. It turns out that, if you want to search only by Name, there is no other solution.Behlke
B
1

Use

cont.GetMethod(action, new [] {typeof(MyViewModel )})
Bukhara answered 29/5, 2013 at 13:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.