如果 c# 委托位于 class 中,则其行为会有所不同

c# delegate behaves differently if it is in a class

我想要一个事件字典,但由于不可能,我使用了一个代表字典。不幸的是,如果委托在 class 中,它的行为会有所不同。在情况 2 的情况下,我无法退订。 为什么取消订阅在 case1 的情况下有效而在 case2 的情况下失败? 我怎样才能重写我的 DummyBroadcaster class 使其工作?

namespace TestApp2
{
    public delegate void StringDelegate(string text);
    class Program
    {
        public static void Main(string[] args)
        {
            var dummySubscriber = new MyDummySubscriber();

            #region case1
            StringDelegate stringDelegate = new StringDelegate(dummySubscriber.CallBack);

            Console.WriteLine($"Case 1-> Invoc lenght:{stringDelegate.GetInvocationList().Length}");
            stringDelegate -= dummySubscriber.CallBack;
            if (stringDelegate is null)
            {
                Console.WriteLine($"Case 1-> All subscribed. Success!!");
            }
            #endregion


            #region case2
            DummyBroadcaster dummyBroadcaster = new DummyBroadcaster();
            dummyBroadcaster.Subscribe(dummySubscriber.CallBack);
            dummyBroadcaster.UnSubscribe(dummySubscriber.CallBack);
            dummyBroadcaster.delegatecontainer["dummykey"].Invoke("Oh noooo.");
            #endregion

            Console.WriteLine("done");
            Console.ReadLine();
        }
    }
    
    class MyDummySubscriber
    {
        public MyDummySubscriber()
        {
        }
        public void CallBack(string str)
        {
            Console.WriteLine($"Callback called. Msg:{str}");
        }
    }
    public class DummyBroadcaster
    {
        public Dictionary<string, StringDelegate> delegatecontainer=new Dictionary<string, StringDelegate>();
        public DummyBroadcaster()
        {
        }

        public void Subscribe(StringDelegate callback)
        {
            if (delegatecontainer.ContainsKey("dummykey") == false)
            {
                delegatecontainer.Add("dummykey",new StringDelegate(callback));
            }
            else if(delegatecontainer["dummykey"] is null)
            {
                delegatecontainer["dummykey"] = new StringDelegate(callback);
            }
            else
            {
                delegatecontainer["dummykey"] += callback;
            }
        }
        public void UnSubscribe(StringDelegate callback)
        {
            var dummyDelegate = delegatecontainer["dummykey"];

            if (dummyDelegate is not null)
            {
                var invocList = dummyDelegate.GetInvocationList();
                bool contains=dummyDelegate.GetInvocationList().Contains(callback);
                dummyDelegate-=callback;
                if (!contains) { Console.WriteLine($"Case 2-> Error. Not subscribed, so cannot unsubscribe. Current invoc list lenght:{dummyDelegate.GetInvocationList().Length}"); }
            }
            if(dummyDelegate is null)
            {
                DoStuffAfterAllUnsubscribed();
            }
            else
            {
                Console.WriteLine($"Case 2-> Unsubscribe failed. Invoc list lenght:{dummyDelegate.GetInvocationList().Length}");
            }
        }
        private void DoStuffAfterAllUnsubscribed()
        {
            Console.WriteLine($"All subscribed. Success!! Invoc list lenght:{delegatecontainer["dummykey"].GetInvocationList().Length}");
        }
    }
}

控制台:

Case 1-> Invoc lenght:1
Case 1-> All subscribed. Success!!
Case 2-> Error. Not subscribed, so cannot unsubscribe. Current invoc list lenght:1
Case 2-> Unsubscribe failed. Invoc list lenght:1
Callback called. Msg:Oh noooo.
done

委托是不可变的对象。如果你做 Delegate + DelegateDelegate - Delegate,你不会改变任何一个委托,而是取回一个新的委托实例。

这意味着如果您这样做:

var dict = new Dictionary<string, Action>();
dict["foo"] = SomeMethod;

var action = dict["foo"];
action -= SomeMethod;

您将存储在字典中的委托引用复制到局部变量 action,然后用 action - SomeMethod 的结果覆盖 action 变量的内容(即null),但您永远不会将其存储回字典中。因此,虽然 actionnull,但 dict["foo"] 仍然包含您插入的原始值。

您需要将 dict["foo"] - SomeMethod 的结果存储回字典中,例如有:

dict["foo"] = action;

或者只是做:

dict["foo"] -= action;

See on dotnetfiddle.net