关于c#delegate创建的性能

时间:2011-07-28 03:40:12

标签: c# reflection delegates

我的项目涉及很多反思。所以,我在字典中缓存了代表。问题是我选择使用MethodInfo作为dict键,我试图使用查找方法,这是这样的:

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

但是,经过一些测试后,我发现用一个函数地址来提供LookUp方法,即在运行中创建过渡代表,有点慢,非常慢:

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

所以,问题是:为了提高性能,我应该改变我的方法,写一些不安全的代码(函数指针甚至是c#支持的吗?)还是有针对这种情况的替代c#式解决方案?< / p>

请帮助我离开那里!

3 个答案:

答案 0 :(得分:1)

前段时间我使用了一个类来进行Winform应用程序中的事件聚合(Mediator),该应用程序的字典缓存类型为Key,Delegate为Value。这堂课看起来像......

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
    }

我猜这与你想要做的有些相似。

不要查看委托本身,而是尝试查找该委托所需的类型。

答案 1 :(得分:1)

通常,从性能角度来看,使用Interfaces总是比使用delegates / reflection更好 您是否可以控制对象使用接口而不是委托?

答案 2 :(得分:0)

委托是封装函数的引用类型,因此它们本质上是函数指针。

在我看来,你正试图实现一种功能库。如果所有函数都与Func的签名匹配,那么使用它并且不要使用通用的Delegate类。

或者,如果要使用Delegate类存储具有不同签名的所有不同类型的委托,则应该使用.DynamicInvoke()方法而不是MethodInfo作为键使用更简单的东西,如字符串或函数返回值或其某些组合。

这是一个简单的例子,说明我对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); 
    }
}