使用初始化语法初始化事件

我经常想写这样的东西:

new Form { Text = "Caption", Controls = { new Button { Text = "Button 1", Click = (s, e) => MessageBox.Show("Button 1 Clicked"), Location = new Point(10, 10) }, new Button { Text = "Button 2", Click = new EventHandler(Button2Clicked), Location = new Point(10, 40) }, new Button { Text = "Button 3", Click = Button3Clicked, Location = new Point(10, 70) }, }, } 

初始化器语法只是糖,为什么编译器无法弄清楚如何为事件订阅生成代码?

给我一些糖,宝贝!

当发明初始化语法时,有人必须考虑事件并拒绝它们。 我一直试图想象一下原理可能是什么,而且我一直空白。

是因为事件是一个可能有多个订阅者的多播对象吗? 不,这是一个初始化过程; 没有其他订阅者。 [更新]不正确,初始化程序在构造后应用,对象可以订阅自己的事件 。

Eric的一个注释:我听说过为什么C#没有实现X语音function 。 在这种情况下,有人已经在那里,实现初始化器。

更新

似乎存在争用/混淆,因为我在我的示例中使用了Click = 。 实际语法与问题无关。 它可以很容易地Click += ,它反映了你必须正常添加处理程序的方式。 我更喜欢前者,因为它与初始化器语法的其余部分一致,但最终我并不关心,只要我能订阅初始化列表中的事件。

另一个更新

我确实意识到现在添加该function可能不太可能。 我想到的第一个问题是Intellisense必须更新。 现在可能有很多其他因素会阻碍添加此function。 我的问题是:他们为什么不首先添加它。 一定有令人信服的东西可以certificate“不可能”的投票。

我看不出有什么理由说他们不能提供这小茶匙糖,我猜他们只是没有!

事件中已经有相当多的语法糖,如果只是在没有提供自己的实现的情况下在类上声明一个事件,编译器就会为你提供一个委托支持字段,以及添加/删除’方法’实现。 另外,当您添加事件处理程序时,编译器使用委托推理,允许您简单地指向方法,而不是创建表示方法的委托。

有趣的是,Mono C#允许您在对象初始值设定项中添加事件处理程序:

http://tirania.org/blog/archive/2009/Jul-27-1.html

是时候切换到Mono 😉

尝试简单地分配一个事件:

 Click = (o,e) => {  } 

不起作用。 初始化程序仅适用于您可以直接分配的内容。 这是因为事件需要能够通知他们想要的任何人(不应该允许您在事故中删除其他人对该事件的注册)。

我不确定这是否是他们的推理,但它对我有用。

领域事件之间存在很大差异。 这里有一篇很好的文章,概述了这些差异,但这就是你的问题的答案:可以为一个字段分配一个值; 一个事件看起来像一个领域,但是一个非常不同的野兽。

编辑

从我链接到的文章:

我们已经看到event关键字是委托声明的修饰符,它允许它包含在接口中,从声明它的类中约束它的调用, 为它提供一对可自定义的访问器(添加和删除) ,以及强制代表的签名

请记住, event是一种捷径; 在幕后,编译器使用add()remove()方法创建一个对象。 喜欢:

 public class Button { public event EventHandler Click { void add {...} void remove {...} } } 

也许这会提供一些见解……:

 Button btn = new Button {Click += (s, e) => MessageBox.Show("hello")}; 

您收到的错误消息是“无法使用集合初始值设定项初始化类型’Button’,因为它不实现IEnumerable”

还有一点需要注意……如果从表单中分配事件处理程序,则可以执行以下操作:

 this.button1.Click += (s, e) => this.textBox1.Text = e.ToString(); 

您无法从您创建的代码中访问表单变量。 我得到了你来自的地方,我并不反对……你正在做的事情可以让你工作。 我想我的观点是有理由为什么决定让它发挥作用。

是的,应该是语言的一部分!

但是,这是一个棘手的解决方法,允许您订阅初始化列表中的事件…

 public class TestClass { public class MyButton : Button { public EventHandler ClickSubscriber { get { return null; } set { Click += value; } } } public static void RunTest() { new Form { Text = "Caption", Controls = { new MyButton { ClickSubscriber = (s, e) => MessageBox.Show("Button 1 Clicked"), }, }, }; } }