如何解决为什么委托不能在容器中添加带有引用的侦听器
我创建了一个
class Program
{
public delegate void TestDelegate();
static void Main(string[] args)
{
Dictionary<int,TestDelegate> delegates = new Dictionary<int,TestDelegate>();
delegates.Add(1,() =>
{
Console.WriteLine("event handler 1");
});
if (delegates.TryGetValue(1,out TestDelegate td))
{
Console.WriteLine($"delegates same Reference {ReferenceEquals(td,delegates[1])}");
td += () => Console.WriteLine("event handler 2");
}
delegates[1] += () => Console.WriteLine("event handler 3");
if (delegates.TryGetValue(1,out TestDelegate td2))
{
td2.Invoke();
}
}
}
解决方法
委托是不可变的对象。 +
运算符返回一个新的委托实例,其调用列表包含两个相加的委托。
你这样做:
delegates.TryGetValue(1,out TestDelegate td);
td += () => Console.WriteLine("event handler 2");
这会将字典中对委托的引用复制到 td
中。 td += ...
然后将 td
的调用列表与您指定的新委托组合到一个新委托实例中,并将对该新委托实例的引用存储在 td
中。
因此,我们已更新 td
以指向一个新的委托实例,但尚未更新 delegates[1]
中保存的引用。当我们稍后访问 delegates[1]
以调用它时,该实例的调用列表将不包含 () => Console.WriteLine("event handler 2")
。
strings
类似:它们是对不可变对象的引用。考虑:
string s1 = "Hello";
string s2 = s1;
s2 += ",World";
Console.WriteLine(s1);
打印“Hello”:+
创建了一个新的字符串实例并将其分配给 s2
,但我们没有更新 s1
以引用该新的字符串实例,并且我们没有改变 s1
所指的字符串。
td += () => Console.WriteLine("event handler 2");
可以扩展为:
td = td + () => Console.WriteLine("event handler 2");
所以你可以看到你只是重新分配给一个局部变量,而不是更新原始委托实例,顺便说一下是不可变的。
另一方面,当你这样做时:
delegates[1] += () => Console.WriteLine("event handler 3");
扩展为:
delegates[1] = delegates[1] + () => Console.WriteLine("event handler 3");
所以你用一个新委托替换字典中的值,即原始和新处理程序的组合。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。