如果 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 + Delegate
或 Delegate - Delegate
,你不会改变任何一个委托,而是取回一个新的委托实例。
这意味着如果您这样做:
var dict = new Dictionary<string, Action>();
dict["foo"] = SomeMethod;
var action = dict["foo"];
action -= SomeMethod;
您将存储在字典中的委托引用复制到局部变量 action
,然后用 action - SomeMethod
的结果覆盖 action
变量的内容(即null
),但您永远不会将其存储回字典中。因此,虽然 action
是 null
,但 dict["foo"]
仍然包含您插入的原始值。
您需要将 dict["foo"] - SomeMethod
的结果存储回字典中,例如有:
dict["foo"] = action;
或者只是做:
dict["foo"] -= action;
我想要一个事件字典,但由于不可能,我使用了一个代表字典。不幸的是,如果委托在 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 + Delegate
或 Delegate - Delegate
,你不会改变任何一个委托,而是取回一个新的委托实例。
这意味着如果您这样做:
var dict = new Dictionary<string, Action>();
dict["foo"] = SomeMethod;
var action = dict["foo"];
action -= SomeMethod;
您将存储在字典中的委托引用复制到局部变量 action
,然后用 action - SomeMethod
的结果覆盖 action
变量的内容(即null
),但您永远不会将其存储回字典中。因此,虽然 action
是 null
,但 dict["foo"]
仍然包含您插入的原始值。
您需要将 dict["foo"] - SomeMethod
的结果存储回字典中,例如有:
dict["foo"] = action;
或者只是做:
dict["foo"] -= action;