首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在c#中订阅(+=)和取消订阅(-=)委托的复杂性是什么?

在c#中订阅(+=)和取消订阅(-=)委托的复杂性是什么?
EN

Stack Overflow用户
提问于 2020-07-27 19:45:46
回答 2查看 173关注 0票数 2

在c#中订阅(+=)和取消订阅(-=)委托的复杂性是什么?

代码语言:javascript
复制
namespace MulticastDelegateDemo
{
    public delegate void MathDelegate(int No1, int No2);

    public class Program
    {
        public static void Add(int x, int y)
        {
            Console.WriteLine("THE SUM IS : " + (x + y));
        }
        public static void Sub(int x, int y)
        {
            Console.WriteLine("THE SUB IS : " + (x - y));
        }
        public void Mul(int x, int y)
        {
            Console.WriteLine("THE MUL IS : " + (x * y));
        }
        public void Div(int x, int y)
        {
            Console.WriteLine("THE DIV IS : " + (x / y));
        }
        
        static void Main(string[] args)
        {
            Program p = new Program();
            MathDelegate del1 = new MathDelegate(Add);
            MathDelegate del2 = new MathDelegate(Program.Sub);
            MathDelegate del3 = p.Mul;
            MathDelegate del4 = new MathDelegate(p.Div); ;

            //In this example del5 is a multicast delegate. We can use +(plus) 
            // operator to chain delegates together and -(minus) operator to remove.
            MathDelegate del5 = del1 + del2 + del3 + del4;
            del5.Invoke(20, 5);
            Console.WriteLine();
            del5 -= del2;
            del5(22, 7);
            
            Console.ReadKey();
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-03 05:07:30

订阅(+=)和取消订阅(-=)实际上是System.Delegate.CombineSystem.Delegate.Remove静态方法调用的简写。对于传递的委托对,它们在内部调用相应的CombineImplRemoveImpl (对于传递了null参数的情况,有一些例外)。

您可以自己在source.dot.net上检查实际的实现。在这里您可以看到,对于MulticastDelegate.CombineImpl复杂度是O(m),其中m是右操作数调用列表中的项数:

代码语言:javascript
复制
Action act = null; int count = 25000; var sw = new Stopwatch();

sw.Restart();
for (int i = 0; i < count; i++)
{
    Action a = () => Console.WriteLine(); 
    act = (a += act);
}
Console.WriteLine($"Subscribe - {count}: {sw.ElapsedMilliseconds}"); // prints "Subscribe - 25000: 1662" on my machine

sw.Restart();
for (int i = 0; i < count; i++)
{
     act += () => Console.WriteLine();
}
Console.WriteLine($"Subscribe - {count}: {sw.ElapsedMilliseconds}"); // prints "Subscribe - 25000: 2" on my machine

至于MulticastDelegate.RemoveImpl,很难快速估计复杂度,但对于n > m的情况,它似乎是O(n) (其中n是正确操作数调用列表中的项数)。

票数 0
EN

Stack Overflow用户

发布于 2020-07-27 20:39:12

实现将依赖于编译器;但是,根据接口、限制和用例,使用链表实现后端将是最简单和最有效的。主要的影响将是取消订阅查找。

你可以在Visual Studio19中多次订阅同一个委托(如果你泄露了几十次,就会对性能造成巨大的影响),所以实现显然只是附加了你给它的东西。

做一个简单的循环测试,订阅的速度要快得多,而取消订阅则会让我的笔记本电脑上的风扇着迷

这使用了StopWatch类和ElapsedMilliseconds -这些类在标准事件声明和方法之外是空的。

代码语言:javascript
复制
Looping 50000 times
Subscribe: 15
Unsubscribe: 9202
代码语言:javascript
复制
        static void Main(string[] args)
        {
            EventSubscirber ms = new EventSubscirber();
            MyEventClass myEventClass = new MyEventClass();

            int loops = 50000;

            Stopwatch swsubscribe = new Stopwatch();
            Stopwatch swunsubscribe = new Stopwatch();

            swsubscribe.Start();
            for (int i = 0; i < loops; i++)
            {
                myEventClass.SampleEvent += ms.SampleEventReceiver;
            }
            swsubscribe.Stop();
            Console.WriteLine($"Looping {loops} times");
            Console.WriteLine($"Subscribe: {swsubscribe.ElapsedMilliseconds}");

            swunsubscribe.Start();
            for (int i = 0; i < loops; i++)
            {
                myEventClass.SampleEvent -= ms.SampleEventReceiver;
            }

            swunsubscribe.Stop();
            Console.WriteLine($"Unsubscribe: {swunsubscribe.ElapsedMilliseconds}");
        }

只是猜测,但基于时间,它每次迭代完整的列表,并取消订阅最后一个匹配的列表。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63114658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档