tags:

views:

1789

answers:

3

Suppose I'm given an object and a string that holds a method name, how can I return a delegate to that method (of that method?) ?

Example:

MyDelegate GetByName(ISomeObject obj, string methodName)
{
    ...
    return new MyDelegate(...);
}

ISomeObject someObject = ...;
MyDelegate myDelegate = GetByName(someObject, "ToString");

//myDelegate would be someObject.ToString

Thanks in advance.

One more thing -- I really don't want to use a switch statement even though it would work but be a ton of code.

+8  A: 

You'll need to use Type.GetMethod to get the right method, and Delegate.CreateDelegate to convert the MethodInfo into a delegate. Full example:

using System;
using System.Reflection;

delegate string MyDelegate();

public class Dummy
{
    public override string ToString()
    {
        return "Hi there";
    }
}

public class Test
{
    static MyDelegate GetByName(object target, string methodName)
    {
        MethodInfo method = target.GetType()
            .GetMethod(methodName, 
                       BindingFlags.Public 
                       | BindingFlags.Instance 
                       | BindingFlags.FlattenHierarchy);

        // Insert appropriate check for method == null here

        return (MyDelegate) Delegate.CreateDelegate
            (typeof(MyDelegate), target, method);
    }

    static void Main()
    {
        Dummy dummy = new Dummy();
        MyDelegate del = GetByName(dummy, "ToString");

        Console.WriteLine(del());
    }
}

Mehrdad's comment is a great one though - if the exceptions thrown by this overload of Delegate.CreateDelegate are okay, you can simplify GetByName significantly:

    static MyDelegate GetByName(object target, string methodName)
    {
        return (MyDelegate) Delegate.CreateDelegate
            (typeof(MyDelegate), target, methodName);
    }

I've never used this myself, because I normally do other bits of checking after finding the MethodInfo explicitly - but where it's suitable, this is really handy :)

Jon Skeet
`return (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), target, methodName);` wouldn't do?
Mehrdad Afshari
It would, unless you're using XNA or Compact Framework. Then, Jon's solution must be used.
Tormod Fjeldskår
Wow - it would indeed, so long as error checking isn't needed. Will edit...
Jon Skeet
I was hoping this would catch your eye! Exactly what I needed -- thanks!
Austin Salonen
Yep CreateDelegate can take a method and resolve to a static or instance method. I'm not sure what framework this is available on, says how this works to call private methods starting with 2.0 but then it says you should target 3.5....I love msdn
JoshBerke
+1  A: 
static MyDelegate GetByName(object obj, string methodName)
{
    return () => obj.GetType().InvokeMember(methodName, 
        System.Reflection.BindingFlags.InvokeMethod, null, obj, null); 
}
Mehrdad Afshari
If the method is incorrect, that will only fail when you try to invoke the delegate, which is generally not as useful as catching the problem early.
Jon Skeet
Yes, It does the job though, and in some circumstances, this might even be desirable.
Mehrdad Afshari
Assuming that the method has no parameters, and if you have to call it more then once you don't mind the overhead
JoshBerke
+1  A: 

Even easier is to use:

    public static MyDelegate GetByName(object target, string methodName)
    {
        return (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), 
               target, methodName);
    }

Notice that CreateDelegate has an overload which takes the methodName for you. This was done with .net 3.5 Sp1

JoshBerke
The MSDN page suggests it's been in since .NET 1.0... http://msdn.microsoft.com/en-us/library/12f294ye.aspx
Jon Skeet
Yep I've been reading that page and it must be just a little confused by the wording in the note on the page.
JoshBerke
I think the 3.5 bit is only about using non-public methods.
Jon Skeet
I thought that as well, but it states: "Starting with the NET Framework version 2.0 Service Pack 1". I guess you could read this as I can write code against .net2.0 but when building I need target .net3.5. Either way its not very clear.
JoshBerke