HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Wrapper for dynamic behavior

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
wrapperbehaviorfordynamic

Problem

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;
  }
}

Solution

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;
}

Code Snippets

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

class B : A
{
    public static void DoAwsomeStuff()
    {
        // different but still awsome stuff.
    }
}
MethodInfo method = null;

foreach(var current in methods)
{
    if(method == null || current.DeclaringType.IsAssignableFrom(method.DeclaringType))
    {
        method = current;
    }
}
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;
}

Context

StackExchange Code Review Q#2184, answer score: 2

Revisions (0)

No revisions yet.