将变量捕获到EventHandler中

我可能会稍微过度思考这一点,但我可以帮助确定一种方法/最好的方法来做到以下几点。 我有一个事件处理程序附加到一个对象,该对象是另一个类的属性。在我的事件处理程序中,我需要有关导致事件的对象的其他元数据(即包含它的对象的ID)。从发件人和事件信息中无法获得我需要的信息。我倾向于这是一个使用捕获变量的好地方,但我不确定我的实现想法。 所以为了在代码中说明我有一个事件处理程序:
void MyEventHandler(object sender, EventArgs e){
    //Do Stuff here
}
(作为一个注释,我在这里使用基本的EventArgs,但在我的实际实现中,它是一个专门的子类,并使用通用的EventHandler声明事件) 我目前正在附加它:
topObject.SubObject.EventToHandle += MyEventHandler;
我后来像这样解决它:
topObject.SubObject.EventToHandle -= MyEventHandler;
我在处理事件时想要topObject的ID,所以我要更改MyEventHandler以获得以下签名:
void MyEventHandler(int id, object sender, EventArgs e)
并附加事件处理程序,如下所示:
topObject.SubObject.EventToHandle += (s,e) => MyEventHandler(topObject.ID, s,e);
我对此的关注是双重的。 一旦我在附加函数之外,处理程序实际上会在没有删除的情况下消失的范围是否存在问题。我曾经看到过一些奇怪的错误,当我使用lambda表达式时,事件处理程序在我身上消失了。它不是所有的时间,只是在某些情况下。任何人都可以告诉我这些情况可能是什么,所以我知道什么时候可以安全使用我的语法。 我记不清楚但是如果我使用这种语法,我认为我不能删除事件处理程序,因为创建的隐式对象不一样。 由于这两个问题,我的想法是创建一个Action并保存动作并使用它直到我需要删除事件处理程序。我做了以下事情:
Action<object, EventArgs> handler = (s,e) => MyEventHandler(topObject.ID, s,e);
topObject.SubObject.EventToHandle += handler;
我知道该动作无法转换为事件处理程序。是否有一些简单的方法可以进行此转换,仍然可以确保我可以分离事件处理程序?我只是在想这个/有没有一种方法我现在没有看到这样做?     
已邀请:
您可以创建包装现有事件处理程序的所有不错的包装器函数,并为它们提供对象ID,但您仍然必须显式存储生成的委托以取消订阅该事件。 我看到没有丑陋包装的唯一好方法是使用反应式扩展。它本质上允许您将事件转换为IObservable,然后您可以将任何运算符应用于生成的IObservable(例如,Select将根据您的情况执行此操作)。但它仍然不那么优雅。     
提升事件的类中的事件处理程序签名应该是:
protected void OnMyEvent(object sender, EventArgs  e)
{
    ....
}
要么
protected void OnMyEvent(object sender, MyEventArgs  e)
{
    ....
}
在这种情况下,调用者会执行以下类型的代码:
topObject.SubObject.MyEvent -= OnSubObjectMyEvent;
并像这样实现OnSubObjectMyEvent(示例):
private void OnSubObjectMyEvent(object sender, MyEventArgs e)
{
   int topObjectId = ((SubObjectType)sender).TopObject.Id;
   ...
}
这里我假设SubObject有一个TopObject属性,允许我获取顶级对象的id。 这就是大多数.NET Framework类的工作方式。这种方法有什么问题吗?     
如果事件处理程序需要顶级对象的Id,我猜它不会破坏你设计中的一些抽象层,让他们意识到彼此。 换句话说,您的事件处理程序可能如下所示:
void Handler(object sender, EventArgs e)
{
     var s = (SubObject) sender;
     int id = s.TopObject.ID;

     // do something with id...
}
我会在发送者和args的约定中保留事件签名。     
不要更改事件的签名。虽然CLR在技术上允许对事件的任何签名,但有理由为整个框架设计具有签名
(object sender, EventArgs args)
的事件。实际上,对于违反此签名的事件,存在一个FxCop规则,CA1009:正确声明事件处理程序:   事件处理程序方法有两个   参数。第一种是类型   System.Object并命名为'sender'。   这是提出的对象   事件。第二个参数是类型   System.EventArgs并命名为'e'。 有几种解决方案(替代方案): 将topObject.ID作为自定义EventArgs的成员传递。 创建一个封装topObject.ID的包装器对象,并将事件处理程序挂钩到此对象的方法。 使用一个闭包范围,该范围可以保留对范围内topObject.ID的引用(这与上面的方法相同,但重量提升是由编译器完成的)     

要回复问题请先登录注册