请考虑以下代码:
public ViewModel()
{
PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
PropertyChanged += ViewModel_PropertyChanged;
}
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
在VisualStudio中,如果键入PropertyChanged +=
,应用程序会提示您按Tab键生成一个类似于构造函数第一行的事件处理程序。但是,在我的构造函数中写第二行也是有效的(并且更简洁)。
这两行有不同的含义吗?如果没有,为什么VisualStudio想生成前者?
答案 0 :(得分:4)
语句语法非常主观,你不能争论味道。但值得注意的是,两种形式的语句都是C#中的语法糖。糖的慢性问题是它会产生腐烂的牙齿。这种语法隐藏了真正的内容,并且永远让C#程序员陷入困境。
首先是简短形式,它完全混淆了编译器实际上在底层创建了一个委托对象。创建对象实际上并不是你想要隐藏在地板垫下的任何东西,就像你想要信任垃圾收集器一直是正确的。不幸的是,它没有,这让程序员遇到麻烦,使用需要函数回调的pinvoke。经典案例是SetWindowsHookEx(),它使用回调让Windows传递钩子事件的通知。这通常是这样编写的:
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
其中 hookProc 是回调方法。这不起作用,保证几秒钟后程序崩溃。 C#编译器自动创建委托对象以允许调用hookProc并将其传递给SetWindowsHookEx函数。麻烦的是,在任何地方都没有对该对象的实时引用。垃圾收集器无法看到本机代码正在使用该对象。因此,当Windows稍后进行回调时,下一次垃圾扫描会破坏对象,这就是Big Kaboom。至少在长形式中,C#程序员意识到他最好将对象引用存储在其他地方。
长形也很麻烦,不够长。它完全混淆了C#编译器实际上创建了一个使用 this 引用的委托对象。当委托目标是实例方法时会发生这种情况。当C#程序员编写如下代码时会出错:
SystemEvents.UserPreferenceChanged +=
new UserPreferenceChangedEventHandler(repaintControls);
其中repaintControls是表单的实例方法,用于在用户更改主题时重新绘制所有控件。这里出现的问题是委托对象捕获 this 的值并将其分配给静态事件。除非您显式编写代码以再次注销事件处理程序,否则永远会保留引用的表单对象。这个要求并不明显,当然不是来自糖,而是Winforms编程中非常罕见的要求。然而,它是一个非常讨厌的内存泄漏错误,当它运行足够长时,它可以很容易地使你的程序在内存不足的异常中崩溃。
嗯,语法都不完美,C#语言不允许像C ++ / CLI这样的完整语法明确指定委托目标的对象。 IDE团队不得不在摇滚和硬地之间挑选。他们选择了岩石。 VS11将拥有艰难的地方,无疑受到大众需求的启发。