Click here to Skip to main content
6,305,776 members and growing! (16,141 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » .NET Framework » General     Advanced License: The GNU General Public License (GPL)

Dynamically Invoke Generic Methods

By Pedro Gomes

Reflection on generics can be complicated. This article shows how to use the DynamicMethod class to dynamically invoke a generic method.
C# (C# 1.0, C# 2.0, C# 3.0), .NET (.NET 2.0, .NET 3.0, .NET 3.5), Dev
Posted:2 Jan 2008
Views:14,994
Bookmarked:38 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
13 votes for this article.
Popularity: 4.79 Rating: 4.30 out of 5
1 vote, 7.7%
1
1 vote, 7.7%
2

3

4
11 votes, 84.6%
5

Introduction

A few days ago, I needed to dynamically invoke a method on a class. Saying only this, things appear very simple.
As usual it got complicated... I figured out that the method was a generic one, and that the class had several overloads defined for the given method.

Background

When embracing this new task, I was obviously concerned with the performance output of the solution, and that's why I opted for the DynamicMethod class (new in .NET Framework 2.0) and Reflection Emit.
There are several pages on the Web that compare the DynamicMethod approach with the Reflection Invoke one, with a very large performance boost for the first one (please read this MSDN magazine article).

To use the DynamicMethod class approach, one must be able to generate the IL code for the method. I have some knowledge on this subject, but you all can do it. Simply code your method in C# or another .NET language, compile it, and then use Lutz Roeder's .NET Reflector to look at the generated IL. With a little persistence you will get the job done.

The Solution

The development output is a simple static class with a few public methods that allow you to create a GenericInvoker for any generic method.

GenericInvoker is a delegate defined as follows.

Note: On methods that have no return value, a call to the delegate will always return null.

public delegate object GenericInvoker(object target, params object[] arguments);

You can create an instance of the GenericInvoker delegate by simply calling one of the overrides for the GenericMethodInvokerMethod method on the DynamiMethods static class (included in the article source code archive).

Note: The GenericInvoker delegate creation can be a slow process. Therefore if you are going to use it in some kind of loop, you should consider caching the value to reduce the performance impact.

Using the Code

Here is a simple example on how to use the supplied DynamicMethods class:

// sample class
public class SampleClass {
  private string instanceName;

  public SampleClass(string instanceName) {
    this.instanceName = instanceName;
  }

  public void Test<TType>(TType s) {
    MessageBox.Show(string.Format("{0} From {1}", s, this.instanceName));
  }

  public string Concatenate<TType>(TType lhs, TType rhs) {
    return string.Format("{0}{1}", lhs, rhs);
  }

  public string Concatenate<TType>(string prefix, TType lhs, TType rhs) {
    return string.Format("{0} - {1}{2}", prefix, lhs, rhs);
  }
}

// Tests class
public class Tests {
  public void Tests() {

    SampleClass instance = new SampleClass("Instance 1");
    GenericInvoker invoker;

    // invoke method that returns void
    invoker = DynamicMethods.GenericMethodInvokerMethod(typeof(SampleClass), "Test", 
        new Type[] { typeof(string) });
    ShowResult(invoker(instance, "this is a tests"));

    // invoke method that returns string, the parameter types are used to find 
    // the correct overload
    invoker = DynamicMethods.GenericMethodInvokerMethod(typeof(SampleClass), 
        "Concatenate", new Type[] { typeof(int) },
      new Type[] { typeof(int), typeof(int) });
    ShowResult(invoker(instance, 100, 200));

    // invoke method that returns string, the parameter types are used to find 
    // the correct overload
    invoker = DynamicMethods.GenericMethodInvokerMethod(typeof(SampleClass), 
        "Concatenate", new Type[] { typeof(int) },
      new Type[] { typeof(string), typeof(int), typeof(int) });
    ShowResult(invoker(instance, "PREFIX", 100, 200));
  }

  // show GenericInvoker result
  private static void ShowResult(object result) {
    if (null == result) {
      MessageBox.Show("return is null");
    } else {
      MessageBox.Show(string.Format("return is {0}", result));
    }
  }
}

Points of Interest

One of the major problems that I faced was related to the GetMethod method from the Type class.
Although GetMethod works very well with normal type methods, it doesn't do so for generic methods. If the generic method has overloads, than the GetMethod call will always return null.

To overcome this limitation, I had to use the GetMethods method and iterate through all the type methods to get the correct one. Here is the code that gets the job done:

private static void FindMethod(Type type, string methodName, Type[] typeArguments, 
        Type[] parameterTypes, out MethodInfo methodInfo,
  out ParameterInfo[] parameters) {

  methodInfo = null;
  parameters = null;

  if (null == parameterTypes) {
    methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
    methodInfo = methodInfo.MakeGenericMethod(typeArguments);
    parameters = methodInfo.GetParameters();
  } else {
     // Method is probably overloaded. As far as I know there's no other way 
     // to get the MethodInfo instance, we have to
     // search for it in all the type methods
    MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
    foreach (MethodInfo method in methods) {
      if (method.Name == methodName) {
         // create the generic method
        MethodInfo genericMethod = method.MakeGenericMethod(typeArguments);
        parameters = genericMethod.GetParameters();

         // compare the method parameters
        if (parameters.Length == parameterTypes.Length) {
          for (int i = 0; i < parameters.Length; i++) {
            if (parameters[i].ParameterType != parameterTypes[i]) {
              continue; // this is not the method we're looking for
            }
          }

           // if we're here, we got the right method
          methodInfo = genericMethod;
          break;
        }
      }
    }

    if (null == methodInfo) {
      throw new InvalidOperationException("Method not found");
    }
  }
}

History

  • 2007.01.02: Initial release

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPL)

About the Author

Pedro Gomes


Member
Been working as a developer and team leader for windows platform projects for almost 10 years

I keep a blog at http://wiggythoughts.blogspot.com/
Occupation: Team Leader
Company: FocusPoint Solutions
Location: Portugal Portugal

Other popular .NET Framework articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 7 of 7 (Total in Forum: 7) (Refresh)FirstPrevNext
GeneralInvalidCastException Pinmemberlobotomy11:18 1 May '09  
GeneralRe: InvalidCastException [modified] PinmemberPedro Gomes21:39 2 May '09  
GeneralRe: InvalidCastException Pinmemberlobotomy4:23 3 May '09  
GeneralBeautiful Pinmembervekaz14:00 4 Mar '09  
GeneralStatic classes PinmemberSteve H. (UK)7:44 6 Mar '08  
GeneralRe: Static classes PinmemberPeregrine10:27 13 Aug '08  
GeneralNice Pinmemberccache7:31 4 Jan '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 1 Jan 2008
Editor: Deeksha Shenoy
Copyright 2008 by Pedro Gomes
Everything else Copyright © CodeProject, 1999-2009
Web18 | Advertise on the Code Project