C#-事件订阅和变量覆盖
我一直在摆弄静态事件,对一些事情很好奇 这是我为这些问题使用和修改的基本代码C#-事件订阅和变量覆盖,c#,.net,events,C#,.net,Events,我一直在摆弄静态事件,对一些事情很好奇 这是我为这些问题使用和修改的基本代码 类程序 { 静态void Main() { aa.col=null; col=新的aa.集合(新[]{“a”,“a”}); aa.evGatherstringa+=col.gatherstring; Console.WriteLine(aa.gatherstring()); //用于问题1 aa.evGatherstringa-=col.gatherstring; col=新的aa.集合(新[]{“b”,“b”});
类程序
{
静态void Main()
{
aa.col=null;
col=新的aa.集合(新[]{“a”,“a”});
aa.evGatherstringa+=col.gatherstring;
Console.WriteLine(aa.gatherstring());
//用于问题1
aa.evGatherstringa-=col.gatherstring;
col=新的aa.集合(新[]{“b”,“b”});
//用于问题2
aa.evGatherstringa+=col.gatherstring;
Console.WriteLine(aa.gatherstring());
}
公共静态aa级
{
公共委托字符串gatherstringa();
公共静态事件gatherstringa evGatherstringa;
公共静态字符串gatherstring(){return evGatherstringa.Invoke();}
公共类集合
{
公共集合(字符串[]字符串){this.strings=strings;}
公共字符串gatherstring()
{
返回此.strings[0];
}
公共字符串[]字符串{get;set;}
}
}
}
输出:
a
b
a
b
a
a
static void Main()
{
aa.col=null;
col=新的aa.集合(新[]{“a”,“a”});
aa.evGatherstringa+=col.gatherstring;
Console.WriteLine(aa.gatherstring());
//用于问题1
//aa.evGatherstringa-=col.gatherstring;
col=新的aa.集合(新[]{“b”,“b”});
//用于问题2
aa.evGatherstringa+=col.gatherstring;
Console.WriteLine(aa.gatherstring());
}
输出:
a
b
a
b
a
a
a
然后是b
static void Main()
{
aa.col=null;
col=新的aa.集合(新[]{“a”,“a”});
aa.evGatherstringa+=col.gatherstring;
Console.WriteLine(aa.gatherstring());
//用于问题1和2
//aa.evGatherstringa-=col.gatherstring;
col=新的aa.集合(新[]{“b”,“b”});
//用于问题2
//aa.evGatherstringa+=col.gatherstring;
Console.WriteLine(aa.gatherstring());
}
输出:
a
b
a
b
a
a
字符串值没有影响。即使两个委托都被调用,您仍然会从第二个委托实例返回字符串
值
至于“为什么这么糟糕?”,嗯……是吗?这取决于上下文。我想说,这是一个很好的例子,说明了为什么应该避免使用委托类型而不是void
返回类型的事件。至少可以这么说,如果有多个返回值,但只看到调用实际返回的其中一个值,这可能会令人困惑
至少,如果您确实为事件使用这样的委托类型,那么您应该愿意接受默认行为,或者将多播委托实例分解为其各自的调用目标(请参阅),并明确决定自己想要哪个返回值
如果您确实知道自己在做什么,并且熟悉多播委托的工作方式,并且对丢失除一个之外的所有返回值(或者在引发事件的代码中显式捕获所有返回值)的想法感到满意,那么我不会说这本身就一定是“坏”的。但它肯定是非标准的,如果不小心执行,几乎肯定意味着代码不能按预期工作。这是不好的。:)
更改代码并删除取消订阅和重新订阅时,Console.WriteLine输出不同。为什么输出不是a然后是b
由于您修改了col
变量,因此您希望以前订阅的事件处理程序会自动引用分配给col
变量的新实例。但这不是事件订阅的工作方式
首次订阅事件时,使用aa.evGatherstringa+=col.gatherstring
,则col
变量仅用于提供对找到事件处理程序方法的aa.collection
实例的引用。事件订阅仅使用该实例引用。事件订阅不观察变量本身,因此以后对变量的更改也不会影响事件订阅
相反,aa.collection
对象的原始实例仍然订阅该事件。即使修改了col
变量,再次引发事件仍会调用原始对象中的事件处理程序,而不是现在分配给col
变量的新对象
更一般地说,您需要非常小心,不要将实际对象与其可以存储在不同位置的引用以及存储在不同位置的任何单个变量混淆