【问题标题】:Is it possible to target an EventHandler in a lambda expression?是否可以在 lambda 表达式中定位 EventHandler?
【发布时间】: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


【解决方案1】:

不,无法定位事件。基本上 event 不是真正的类型成员,而只是产生 add_EventName 和 remove_EventName 方法对的 C# 语法。

您可以尝试引用这些内部方法名称,但在 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 调用)替换了一个令人头疼的问题(正确的事件命名)。不过,这将有助于重命名。

【讨论】:

    猜你喜欢
    • 2010-12-03
    • 2017-04-19
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2021-08-27
    • 1970-01-01
    相关资源
    最近更新 更多