简体   繁体   中英

Efficient use of reflection in C#

I'm writing a library in C# that I will later use for an application, and I want the library to be as efficient as sanely possible (ie. don't over-complicate things too much to make it more efficient). However, I have this question about how to most efficiently use reflection on a class/methods and to illustrate the question I've simplified my class a lot down to this:

class MyClass
{
    private static Dictionary<string, object> methods;

    public void Method1()
    {
        // Do something.
    }

    public void Method2()
    {
        // Do something else.
    }
}

Now, what I want is from within the class (a private method yet to be created), take a string containing the method-name, then fire the method, simple as that. The easiest way of doing this would be to just look at the name, get a method with that name, and execute it, but that forces me to use reflection a lot of times. This private method can potentially be called thousands or tens of thousands of times, and it need to be quick. So I came up with two possible solutions. As you can probably see I've added a static dictionary containing string->object (replacing object with actual type, just wrote object cause that works with both my examples). Then I'd add a static constructor that goes trough the class and adds all the methodinfos to the methods-dictionary. And then comes the question, on creation of a new instance of the class, should I create bound delegates to the methods and put those in a non-static private dict, or should I simply fire the methods using the MethodInfo in the methods-dictionary?

The average use-case will create 10 instances of this class, and have 1000+ calls to the method that should fire either Method1 or Method2 depending on it's string-argument (and no, switch-case is not an option because of the extensibility of the class, as said, this was a simplified version). What would be the most efficient way of achieving this?

Obviously no one can answer the question without actually trying it and doing performance tests to see if your goal is met or not.

Reflection is a lot faster in modern versions of the framework than it used to be, but it still is not as fast as simply invoking a delegate.

My suggestion would be to start with your proposed solution: build the cache of method infos once:

class MyClass
{
    static Dictionary<string, MethodInfo> cache = new ...
    public void InvokeByName(string name)
    {
        MethodInfo methodInfo = GetMethodInfoFromCache(name);
        methodInfo.Invoke(this, new object[] {});
    }

When asked to invoke a method identified by a string on a particular instance as the receiver, look up the method info by name and then invoke it with the given receiver. Measure the performance of that and see if it meets your goal. If it does, great; don't waste any more of your valuable time trying to make something faster that is already fast enough.

If that is not fast enough then here's what I'd do:

class MyClass
{
    static Dictionary<string, Action<MyClass>> cache = new ...
    public void InvokeByName(string name)
    {
        GetActionFromCache(name).Invoke(this);            
    }

So what does GetActionFromCache do? If there is already an action in the cache, we're done. If there is not, then obtain the MethodInfo via Reflection. Then use the Expression Tree library to build up a Lambda:

var methodInfo = SomehowGetTheMethodInfo(name);
// We're going to build the lambda (MyType p)=>p.<named method here>()    
var p = Expression.Parameter(typeof(MyType), "p"));
var call = Expression.Call(p, methodInfo);
var lambda = Expression.Lambda<Action<MyType>>(call, p);
var action = lambda.Compile();

And now you have an action in hand that you can invoke with the instance. Stick that thing in the cache.

This is, incidentally, at an incredibly simplified level, how "dynamic" works in C# 4. Our problem is enormously complicated by the fact that we have to deal with the receiver and arguments being of any type. You have it very easy comparatively.

Since you will obtain all of the MethodInfo instances and the name to map them to (presumably through the MethodInfo.Name property, you can go one step further and create a compiled lambda expression in the form of a delegate which you can execute.

First, it's assumed that all of your methods will have the same signature. In this case, it's an Action<T> delegate . With that, your dictionary will look like this:

// No need to have the dictionary **not** readonly
private static readonly IDictionary<string, Action<MyClass>> methods =
    new Dictionary<string, Action<MyClass>>;

Then, in your static constructor, you would use reflection to get all of the MethodInfo instances:

static MyClass()
{
    // Cycle through all the public instance methods.
    // Should filter down to make sure signatures match.
    foreach (MethodInfo methodInfo in typeof(MyClass).
        GetMethods(BindingFlags.Public | BindingFlags.Instance))
    {
        // Create the parameter expression.
        ParameterExpression parameter = Expression.
            Parameter(typeof(MyClass), "mc");

        // Call the method.
        MethodCallExpression body = Expression.Call(pe, methodInfo);

        // Compile into a lambda.
        Action<MyClass> action = Expression.Lambda<Action<MyClass>>(
            body, parameter).Compile();

        // Add to the dictionary.
        methods.Add(methodInfo.Name, action);
    }
}

Then, your private method would look like this:

private void ExecuteMethod(string method)
{
    // Add error handling.
    methods[method]();
}

The benefit here is that you get the performance of compiled code, while paying a very small price (IMO) in code complexity (in creating the delegate). Granted, there is a slight overhead in calling the code through a delegate, but that's been vastly improved (it had to be with the introduction of LINQ, since they would be executed many, many times).

If I had the choice here, I would probably go with Henk's suggestion and use dynamic. Method invocations are blazingly fast (much faster than ordinary reflection and almost like normal method calls).

You may also find inspiration by looking at this class , which extends DynamicObject and illustrates how you could do the dynamic invocation of methods.

However, if you wish to support 3.5 or keep your options open and you have no objections to using a 3rd party library , then this can still be fairly easily accomplished:

void Invoke( string methodName )
{
    this.CallMethod( methodName );
}

CallMethod creates a DynamicMethod delegate for invoking that particular method and caches it in case you call the same method again. There are also extensions for invoking methods with parameters and a ton of other useful reflection helpers.

If you prefer to cache the delegate yourself (we use a ConcurrentDictionary and WeakReferences to do this, which means it might get garbage collected), just call DelegateForCallMethod instead.

The library supports both 3.5 and 4.0. WP7 does not support Reflection.Emit and therefore cannot use IL generation and DynamicMethod. However, WP 7.5 does support this (but Fasterflect, as the library is called, does not yet support it).

From your comment:

Well, simply put it's connected to a server, the server sends commands in the form of <name> <param1> <param2> ... <paramN>, and the name determines what functionality should be performed. I want to be able to just add functions with matching names (or rather, I've created an attribute that lets me name methods other than their method-name cause command-names might be numeric), cause the list of names is looooong, and I don't want to do a switch-case.

You can solve this problem with a simple command interface and a table-driven factory for a matching instance (or a type, if the command instances are not reusable).

public interface ICommand {
  void Execute();
}

public class Processor {
  private static Dictionary<string, ICommand> commands;
  static Processor() {
    // create and populate the table
  }
  public void ExecuteCommand(string name) {
    // some validation...
    commands[name].Execute();
  }
}

No reflection involved.

To create a new command, just create a new class that implements ICommand and add the corresponding line to the commands table inside the Processor static constructor.

public class FooCommand : ICommand {
  public void Execute() {
    // foo away!
  }
}

...

public class Processor {
  static Processor() {
    ...
    commands["foo"] = new FooCommand();
    ...
  }
}

There are many advantages to this design, aside from performace. Your commands are isolated from each other, changes to one command or the creation of new commands won't impact other commands. They're better testable and easier to maintain. Even the processor can be closed (in an OCP way) if you can maintain your table in a config file or a database, for example.

You can certainly find alternative designs and ways to pass parameters to the commands, but I hope this gives you the basic idea.

In this particular case you can declare your dictionary slightly differently and get the result you are after::

class MyClass
{
    private static Dictionary<string, Action<MyClass>> methods;

    public void Method1()
    {
        // Do something.
    }

    public void Method2()
    {
        // Do something else.
    }
    static MyClass(){
       methods = new Dictionary<string, Action<MyClass>>();
       foreach(var method in typeof(MyClass).GetMethods(
               BindingFlags.Public | BindingFlags.Instance)
       )
        {
            methods.Add(
                method.Name,
                Delegate.CreateDelegate(typeof(Action<MyClass>),method) 
                  as Action<MyClass>);
        }
    }
}

This code has the advantage of not using code generation. However if you have methods of different signatures then a different approach will be needed. Here we are creating open instance delegates. (Note this doesn't always work correctly if MyClass is a struct or if any of these methods are generic virtual methods).

The fastest way of doing something is not to do it at all. Have you considerer just making interface like:

interface ICallMe 
{
 void CallByName(string name, object args);
}

This way if some of the implemetations wants to be insanely smart it can do reflection+caching+IL generation, the others can simply use if/switch.

Downside - significantly less fun to implement and debug.

Invoking a MethodInfo is slow. So I think creating a new dictionary for each instance should be good enough. Another option is to create a delegate that accepts the instance ( Action<MyClass> ) using Expressions (and then store them in the static dictionary):

MethodInfo method = typeof(MyClass).GetMethod("Method1");

var parameter = Expression.Parameter(typeof(MyClass));

var call = Expression.Call(parameter, method);

var lambda = Expression.Lambda<Action<MyClass>>(call, parameter);

Action<MyClass> del = lambda.Compile();

Have you considered using Code Generation and T4 Text Templates ?

http://msdn.microsoft.com/en-us/library/bb126445.aspx
http://msdn.microsoft.com/en-us/library/bb126478.aspx

Then you could use a case statement.

Something like

partial Class MyClass
{
    public void Exec(string funcToExec)
    {
        swtich(funcToExec)
        {
            <#
            foreach(MethodInfo mi in 
                typeof(MyClass).GetMethods(BindingFlags.Public | BindingFlags.Static)
            { 
                if(mi.Name != "Exec"){
            #>
            case : "<#= mi.Name #>"
                <#= mi.Name #>();
            <#
            }}
            #>
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM