views:

63

answers:

2

After generating a type dynamically and calling TypeBuilder.CreateType, I want to create a delegate that points to a method in the new type. But if I use code like

loadedType = typeBuilder.CreateType();
myDelegate = (MyDelegate)Delegate.CreateDelegate(
                                  typeof(MyDelegate), methodBuilder);

Reusing the methodBuilder as a methodInfo, I get the exception "MethodInfo must be a RuntimeMethodInfo". Now normally I can re-acquire the MethodInfo with

MethodInfo mi = loadedType.GetMethod(methodBuilder.Name);
myDelegate = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), mi);

But my class may contain several overloaded methods with the same name. How do I make sure I get the right one? Do methods have some persistent identifier I could look up in loadedType?

Update: okay, here's what I'm using to re-acquire the MethodInfo. I just wish I could be sure it works in all cases.

private static MethodInfo ReacquireMethod(Type type, MethodInfo method)
{
    BindingFlags flags = BindingFlags.DeclaredOnly;
    flags |= (method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
    flags |= (method.IsStatic ? BindingFlags.Static : BindingFlags.Instance);
    MethodInfo m = type.GetMethod(method.Name, flags, null,
                                          ParameterTypes(method), null);
    Debug.Assert(m != null);
    return m;
}
A: 

You need to use the GetMethod overload that takes an array of types. Method overloads are selected for binding by the parameters passed to them. Since you are not actually calling a method when getting their metadata via reflection, you have to provide an ordered array of Type objects to get the right MethodInfo object:

Type.GetMethod Method (String, Type[])

Used like:

MethodInfo mi = loadedType.GetMethod(
    methodBuilder.Name, 
    new[] 
    { 
        typeof(string), 
        typeof(int) 
    }
);

Assiming methodBuilder.Name is "MyMethod", that would bind the following:

public <returnType> MyMethod(string param1, int param2);

Remember that the return type is not a part of a method signature, only the method name and its parameter types are.

jrista
+3  A: 

As far as I'm aware there's no persistent shared identifier.

Overloads of a method are distinguished by their parameter lists, so my guess is that you'll need to call GetParameters on methodBuilder and then translate the returned ParameterInfo[] array into a Type[] array to pass to the the appropriate GetMethod overload:

MethodInfo mi = loadedType.GetMethod(
    methodBuilder.Name,
    methodBuilder.GetParameters().Select(p => p.ParameterType).ToArray());
LukeH
I rather thought somebody would suggest this kind of lookup. While fairly reliable it's not 100%, I think, bacause what if you have two overloads, the only difference between them being one is 'out' and one is 'ref'?
Qwertie
Ah, the C# compiler won't allow two overloads that differ only by 'ref' and 'out'. Perhaps your method really will work 100% reliably, I guess I will go for it. It's a slight pain though, as I'm using .NET 2.0 - no LINQ.
Qwertie
One problem though, GetMethod only gets public methods. I should use a different overload to be safe.
Qwertie