举一个简单的例子,如果我有某种按钮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.
我一直在为一些项目愉快地使用它,但它有它的缺点,其中最大的一个是使用硬编码的事件名string
。这使得事件名称更改变为运行时异常,并且确定事件的使用是困难的。
我开始尝试制作一个版本,允许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表达式的人所污染。我希望我在这里找不到明显的东西。
答案 0 :(得分:1)
不,无法定位事件。基本上事件不是真正的类型成员,而只是C#语法,它产生add_EventName和remove_EventName方法对。
您可以尝试引用这些内部方法名称,但在C#中不可能 - http://msdn.microsoft.com/en-us/library/z47a7kdw.aspx
SO中有许多类似的问题,答案是否定的 - 就像Jon Skeet https://stackoverflow.com/a/4756021/2170171
如果你真的疯了,你可以试试像
这样的东西private static void Subscribe(Action addHandler)
{
var IL = addHandler.Method.GetMethodBody().GetILAsByteArray();
// Magic here, in which we understand ClassName and EventName
???
}
使用类似
Subscribe(() => new Button().Click += null);
您可以尝试使用Cecil http://www.mono-project.com/Cecil来分析IL,或者实现您自己的逻辑,因为它对于可预测的代码行来说应该不会太难。
我认为这不是一个好的解决方案,因为它只是将一个头痛(正确的事件命名)替换为另一个(正确的Subscribe
调用)。虽然,它有助于重命名。