开发者

About the performance of c# delegate creation

My project involved a lot of reflection. So, I cached delegates in dictionaries. The problem is that I chose to use MethodInfo as dict keys, I've tried to use a look-up method, which is something like this:

Func<T,R> LookUp(Func<T,R> m)
{
  return (Func<T,R>)dict[m.Method];
}
//LookUp(MyCls.Method)

But, after doing some tests, I found out that feeding the LookUp method with a function address, i.e, creating transitional delegates on the fly, is kinda slow,very slow indeed:

class MyCls
{
    public static void Operate(int whatever){ }
}

class MainClass
{
    delegate void Doer<T>(T arg);
    static Dictionary<MethodInfo,Delegate> _dict = new Dictionary<MethodInfo,Delegate>();

public static void Main (string[] args)
    {
        Action<int> dg = MyCls.Operate;
        _dict[dg.Method] = Delegate.CreateDelegate(typeof(Action<int>),dg.Method);

        //performance test
        var start = Environment.TickCount;          
        for (int i = 0; i < 10000000; i++)
        {
            //LookUp(dg);//11               
            //LookUp<int>(MyCls.Operate);//1503
            //new MyCls();//431
        }

        Console.WriteLine (Environment.TickCount-start);
    }
    static  Action<T> LookUp<T>(Action<T> dg) 
    {
        //should return (Action<T>)_dict[dg.Method];
        return null;
    }

So, the question is: To improve the performance, should I change my approach, and write some unsafe code (Are function pointers even supported by c#?) or is there altern开发者_运维技巧ative c#-style solutions for this kind of situations?

Please, help me out of there!


I used a class some time ago for event aggregation (Mediator) in a Winform application that had a dictionary cache of Type as key and Delegate as Value. The class looks something like...

public sealed class EventAggregator
    {
        #region Fields

        private readonly Dictionary<Type, List<Object>> subscribers = new Dictionary<Type, List<Object>>();

        #endregion

        #region Public Methods

        public void Subscribe<TMessage>(Action<TMessage> handler)
        {
            if (subscribers.ContainsKey(typeof(TMessage)))
            {
                var handlers = subscribers[typeof(TMessage)];
                handlers.Add(handler);
            }
            else
            {
                var handlers = new List<Object> {handler};
                subscribers[typeof(TMessage)] = handlers;
            }
        }

        public void Unsubscribe<TMessage>(Action<TMessage> handler)
        {
            if (subscribers.ContainsKey(typeof(TMessage)))
            {
                var handlers = subscribers[typeof(TMessage)];
                handlers.Remove(handler);

                if (handlers.Count == 0)
                {
                    subscribers.Remove(typeof(TMessage));
                }
            }
        }

        public void Publish<TMessage>(TMessage message)
        {
            if (subscribers.ContainsKey(typeof(TMessage)))
            {
                var handlers = subscribers[typeof(TMessage)];
                foreach (Action<TMessage> handler in handlers)
                {
                    handler.Invoke(message);
                }
            }
        }

        #endregion
    }

which i guess is somewhat similar to what you are trying to do.

Instead of looking up on the delegate itself, try looking up on the type which that delegate is required for.


In general using Interfaces will always be better from a performance perspective than using delegates/reflection.
Do you have control of the objects to use an interface instead of delegates?


Delegates are reference types that encapsulate a function, so essentially they are function pointers.

It seems to me that you are trying to achieve a sort of function repository. If all the functions are going to match the signature of Func then use that and dont use the generic Delegate class.

Alternatively if you want to store all different kinds of delegates with different signatures, using the Delegate class, you should probably use the .DynamicInvoke() method and instead of MethodInfo as your key use something simpler, like a string, or the functions return value, or some combo thereof.

Here's a simple example of what I mean with various techniques for LookUp,

class FunctionRepository : List<Delegate> // could also be a Dictionary<,>
{
    public R Invoke<R>(string name, params object[] args)
    {
        var _delegate = this.Single(x => x.Method.ReturnType == typeof(R)
            && x.Method.Name == name);

        return (R)_delegate.DynamicInvoke(args);
    }  

    public Func<R> LookUp<R>(string name, params object[] args)
    { 
        var _delegate = this.Single(x => x.Method.ReturnType == typeof(R) 
            && x.Method.Name == name);

        return () => (R)_delegate.DynamicInvoke(args); 
    }

    public Func<Object[], R> LookUp<R>(string name)
    { 
        var _delegate = this.Single(x => x.Method.ReturnType == typeof(R) 
            && x.Method.Name == name);

        return (args) => (R)_delegate.DynamicInvoke(args); 
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜