8

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.

Mansfield
  • 14,445
  • 18
  • 76
  • 112

3 Answers3

4

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>();
Ani
  • 111,048
  • 26
  • 262
  • 307
  • Trying it now. I am concerned about the efficiency since this code runs for every single request. – Mansfield May 29 '13 at 13:51
  • 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). – Ani May 29 '13 at 13:52
  • 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`)!?! – Alex Filipovici May 29 '13 at 13:54
  • I hadn't gotten that far, though I may well end up doing that. – Mansfield May 29 '13 at 13:54
  • 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. – Ani May 29 '13 at 13:55
  • 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. – Mansfield May 29 '13 at 13:58
2

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

Johannes Wanzek
  • 2,825
  • 2
  • 29
  • 47
1

Use

cont.GetMethod(action, new [] {typeof(MyViewModel )})
vborutenko
  • 4,323
  • 5
  • 28
  • 48