是否可以在lambda表达式中定位EventHandler? [英] Is it possible to target an EventHandler in a lambda expression?

查看:112
本文介绍了是否可以在lambda表达式中定位EventHandler?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

举一个简单的例子,如果我有某种按钮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 strings. 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.

您可以尝试引用这些内部方法的名称,但是在C#中是不可能的-

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆