【发布时间】:2014-02-20 19:48:47
【问题描述】:
举个简单的例子,如果我有某种按钮 UI 类,我是否可以编写一个函数来接受一个指向其 Click 事件处理程序的表达式:
SomeMethod<SomeButtonClass>(button => button.Click);
我正在尝试消除一些当前用于系统的魔术字符串,以使事件可等待。有问题的代码来自blog post by Frank Krueger(如果您需要一些背景知识,值得一读)。
public static Task<TEventArgs> GetEventAsync<TEventArgs>(this object eventSource, string eventName) where TEventArgs : EventArgs {
//...
Type type = eventSource.GetType();
EventInfo ev = type.GetEvent(eventName);
//...
}
虽然里面的细节可能并不重要,但完整的方法允许您使用Event 触发作为Task 的完成源,从而更容易使用await 进行管理。对于引发事件的某些类,您可以通过简单的调用基于该事件绑定到 Task。
Task<EventArgs> eventTask = someEventCausingObject.GetEventAsync<EventArgs>("SomeEventHandler");
// traditionally used as someEventCausingObject.SomeEventHandler += ...;
await eventTask;
// Proceed back here when SomeEventHandler event is raised.
我在几个项目中愉快地使用了它,但它有它的缺点,其中一个最大的缺点是使用硬编码的事件名称strings。这使得事件名称更改变成运行时异常,并且很难确定事件的使用情况。
我开始尝试制作一个允许EventHandler 作为Expression 的一部分传入的版本,目标如下:
await someEventCausingObject.GetEventAsync<EventCausingClass, EventArgs>(x => x.SomeEventHandler);
...带有相应的方法签名...
public static Task<TEventArgs> GetEventAsync<TSource, TEventArgs>(this TSource eventSource, Expression<Func<TSource, EventHandler>> eventHandlerExpression) where TEventArgs : EventArgs {
//...
}
不幸的是,调用代码中的 lambda 表达式导致编译错误:
Error CS0070: The event `SomeEventHandler' can only appear on the left hand side of += or -= when used outside of the type `EventCausingClass'.
考虑到事件处理程序的典型使用方式,这是有道理的,但我希望能找到比预先指定的字符串名称更好的解决方案。似乎搜索“表达式”和“事件处理程序”的组合都倾向于被描述 lambda 表达式以开始 += 事件处理程序分配的人所污染。我希望我在这里遗漏了一些明显的东西。
【问题讨论】:
-
简短的回答是否定的。您没有遗漏什么,只是无法使用该语法。
-
另请注意,Button.Click 可以包含多个附加到它的事件处理程序,这与您在此处为一个特定事件处理程序提取信息的逻辑相反。
-
@DavidKhaykin 他想做的是获取对事件的引用,以便可以添加处理程序,而不是查看那里的处理程序。
-
谢谢。在我的狩猎中,我肯定错过了这个问题。这是一本有趣的书,当然,看到他们异步化类中所有事件的方法,尽管我在 Xamarin 环境中,可能无法复制他们的努力。
标签: c# lambda event-handling