4
\$\begingroup\$

I am writing a wrapper for dynamic behavior in C#. If I use GetMethod(), then an exception is thrown when there is more than one method (overloads). I figure it will become apparent at runtime that if there is an argument mismatch anyway. Is this a good way to solve the problem?

public class StaticMembersDynamicWrapper : DynamicObject
{
  private Type _type;

  public StaticMembersDynamicWrapper(Type type) { _type = type; }

  // Handle static methods
  public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
  {
     var methods = _type
        .GetMethods(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public)
        .Where(methodInfo => methodInfo.Name == binder.Name);

     var method = methods.FirstOrDefault();
     if (method != null)
     {
        result = method.Invoke(null, args);
        return true;
     }

     result = null;
     return false;
  }
}
\$\endgroup\$
2
\$\begingroup\$

The order the method infos are returned in dose not appear to be a defined one, I would suggest filtering on argument types to avoid the risk of it all crumbling to dust when the order changes.

Also you may want to consider the case when a method is defined on both the base class and the subclass.

class A
{
    public static void DoAwsomeStuff()
    {
        // really awsome stuff.
    }
}

class B : A
{
    public static void DoAwsomeStuff()
    {
        // different but still awsome stuff.
    }
}

Hiding static methods like this should probably be frowned upon, but all the same I would suggest selecting the method with the most specific declaring type. Just to be safe.

MethodInfo method = null;

foreach(var current in methods)
{
    if(method == null || current.DeclaringType.IsAssignableFrom(method.DeclaringType))
    {
        method = current;
    }
}

Edit:

Another possibility worth exploring is the use of Type.InvokeMember(). This already takes the argument types and method hiding into account for you.

try
{
    result = _type.InvokeMember(
        binder.Name,
        BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.InvokeMethod,
        null,
        null,
        args
        );

    return true;
}
catch(MissingMethodException)
{
    result = null;
    return false;
}
\$\endgroup\$
1
  • \$\begingroup\$ I am using this with simple value types, such as int or double. This means that the inheritance scenario is not a plausible one. Sounds like a good thing to guard for with, possibly, a code contract. I am much more interested in the aspect of multiple overloads. But that sounds more like a StackOverflow question. \$\endgroup\$
    – GregC
    May 1 '11 at 1:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.