是否可以在lambda表达式中定位EventHandler? [英] Is it possible to target an EventHandler in a lambda expression?
问题描述
举一个简单的例子,如果我有某种按钮UI类,我是否可以编写一个函数,该函数采用指向其Click
事件处理程序的表达式:
For a simple example, if I had some sort of button UI class, could I write a function that takes an expression that points to its Click
event handler:
SomeMethod<SomeButtonClass>(button => button.Click);
我正在尝试消除一些当前用于系统的不可思议的字符串,以使事件可以等待.有问题的代码来自弗兰克·克鲁格(Frank Krueger)的博客帖子(如果您需要一些背景知识,则值得一读).
I'm trying to eliminate some magic strings currently being used for a system to make events awaitable. The code in question is derived from a blog post by Frank Krueger (a worthwhile read, if you want some background).
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
.
While the specifics inside probably aren't important, the full method allows you to use an Event
triggering as the completion source for a Task
, making it easier to manage with await
. For some class that raises an event, you can tie into a Task
based on that event with a simple call.
Task<EventArgs> eventTask = someEventCausingObject.GetEventAsync<EventArgs>("SomeEventHandler");
// traditionally used as someEventCausingObject.SomeEventHandler += ...;
await eventTask;
// Proceed back here when SomeEventHandler event is raised.
我已经很高兴地在几个项目中使用了它,但是它有缺点,最大的缺点之一就是使用了硬编码的事件名称string
.这使得事件名称更改变成运行时异常,并且确定事件的用法很困难.
I have been using this happily for a couple projects, but it has its drawbacks, one of the biggest being the use of hard-coded event name string
s. This makes event name changes turn into runtime exceptions, and determining usage of the event is difficult.
我开始尝试制作一个版本,该版本允许EventHandler
作为Expression
的一部分传递,目的是这样的:
I started trying to make a version that would allow the EventHandler
to be passed in as part of an Expression
with the goal of something like this:
await someEventCausingObject.GetEventAsync<EventCausingClass, EventArgs>(x => x.SomeEventHandler);
...具有相应的方法签名...
...with the corresponding method signature...
public static Task<TEventArgs> GetEventAsync<TSource, TEventArgs>(this TSource eventSource, Expression<Func<TSource, EventHandler>> eventHandlerExpression) where TEventArgs : EventArgs {
//...
}
不幸的是,调用代码中的lambda表达式会导致编译错误:
Unfortunately, the lambda expression in the calling code causes a compile error:
Error CS0070: The event `SomeEventHandler' can only appear on the left hand side of += or -= when used outside of the type `EventCausingClass'.
考虑到通常如何使用事件处理程序,这是有道理的,但是我希望找到一种比预先指定的字符串名称更好的解决方案.似乎搜索"expression"和"eventhandler"的组合都容易受到人们描述开始+=
事件处理程序分配的lambda表达式的污染.我希望这里缺少明显的东西.
This makes some sense given how event handlers are typically used, but I was hoping to find a better solution going forward than the pre-specified string name. It seems searches for combinations of "expression" and "eventhandler" all tend to be polluted with people describing lambda expressions for beginning +=
event handler assignment. I'm hoping I am missing something obvious here.
推荐答案
否,无法定位事件.基本上,event不是真正的类型成员,而只是C#语法,该语法产生add_EventName和remove_EventName方法对.
No, it is not possible to target an event. Basically event is not a real type member, but just C# syntax which produces add_EventName and remove_EventName methods pair.
You could try refer to these internal methods name, but it's not possible in C# - http://msdn.microsoft.com/en-us/library/z47a7kdw.aspx
SO中有许多类似的问题,但答案相同-像乔恩·斯凯特(Jon Skeet)的回答 https://stackoverflow.com /a/4756021/2170171
There are many similar questions in SO, with the same answer NO - like this one from Jon Skeet https://stackoverflow.com/a/4756021/2170171
如果您真的疯了,可以尝试类似的操作
If you're real crazy, you can try something like
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,或实施您自己的逻辑,因为对于可预测的代码行来说,它应该不会太难.
You could try using Cecil http://www.mono-project.com/Cecil for analyzing IL, or implement your own logic as it should not be too hard for predictable line of code.
我认为这不是一个好的解决方案,因为它只是用另一种(正确的Subscribe
调用)代替了一种头痛(正确的事件命名).不过,它将有助于重命名.
I don't think that it is good solution though, as it just replaces one headache (proper event naming) with another one (proper Subscribe
calling). Though, it will help with rename stuff.
这篇关于是否可以在lambda表达式中定位EventHandler?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!