在订阅了另一个对象的事件的委托中使用 (object sender)

Posted

技术标签:

【中文标题】在订阅了另一个对象的事件的委托中使用 (object sender)【英文标题】:Using (object sender) in a delegate subscribed to an event of another object 【发布时间】:2013-08-25 18:41:35 【问题描述】:

假设我有 2 个类,A 类和 B 类。对象 A(属于 A 类)包含一些对象 B(属于 B 类)。 B 对象有一个事件,并且对象 A 订阅了一个委托,该委托在(任何这些 B 对象的)事件被引发时执行。

private void fooEventHandler(object sender, EventArgs e)

...

在 fooEventHandler 中执行某些操作后(必须在 A 中完成),我想向引发事件的 B 对象发出我在 fooEventHandler 中所做的结果的信号。所以我做了以下事情:

private void fooEventHandler(object sender, EventArgs e)  
    
    ...

        if (allOK)
           ((classB)sender).isOK();
        else
          ((classB) sender).isNotOK();
    

所以我实际上是在事件发生后使用发送方调用 objectB 上的特定方法。我这样做是为了避免将一些从设计角度来看不应该在 objectB 中的 objectA 成员传递给 objectB(在他的构造函数中)。这是处理问题的合理方法吗?这种方式使用(object sender)是否常见?

【问题讨论】:

isNotOK()。以 CancelEventHandler 委托为例。 嗯..你可以更具体一点吗?我正在查看 CancelEventHandler 但我不明白你的意思... 如果是你的事件,最好定义一个以 classB 作为参数而不是对象的处理程序 不错的建议 Vadim,但微软的最佳实践不是建议每个事件处理程序方法都有一个签名,如 (object sender someEventargs e)?无论如何,除此之外,我的代码还可以吗?仍然想知道 Hans Passant 是什么意思…… 【参考方案1】:

我认为你让你的 A 类与你的 B 类太耦合了。如果在处理事件后您需要 A 做的就是调用某个回调 - 然后传递回调。这样,您可以传递例如 lambda 表达式,或传递与 B 或其他相关的类的方法。

所以-

private void fooEventHandler(Action p_okCallback, Action p_notOkCallback)  

    ...

    if (allOK)
       p_okCallback();
    else
      p_notOkCallback();

或 -

private void fooEventHandler(Action<bool> p_callback)  
       
    ...

    p_callback(allOk);

如果事件不在你的控制之下,你可以按照 Helmer 的建议和从 EventArgs 继承。但同样 - 我会传入回调,而不是类本身。

另一种选择 - 如果您觉得需要多个方法并且对传递十几个回调感到尴尬 - 考虑使用您需要的方法传递一个接口。

【讨论】:

【参考方案2】:

这是一个解决方案,但我认为这不是更好的方法。

这是另一个解决方案

第 1 步: - 创建一个 EventArgs 的继承类,并在其上添加一些属性,这些属性定义要在 B 类中执行的处理

示例:

public class ClassBEventArgs : EventArgs

    bool treatmentIsOK = false;

第 2 步: 在 Class B 的同一个命名空间中创建一个新的 Delegate Event 定义并使用它来声明事件

示例:

namespace ClassBNameSpace

   public delagate fooEventHandlerDelegate void (object sender, ClassBEventArgs e);

   public ClassB 
   

   public event fooEventHandlerDelegate fooEventHandler;

   .........

第三步: 在 ClassB 中,使用 ClassBEventArgs 对象引发 fooEventHandler 事件。 在 ClassA 事件处理程序中设置treatmentIsOK EventArgs 的正确值。当事件从ClassA回调到ClassB时,可以利用treatmentIsOK属性的值

样品:

.......
if (this.fooEventHandler != null)

    ClassBEventArgs customEventArgs = new ClassBEventArgs();
     this.fooEventHandler (this,customEventArgs);
     if (customEventArgs.treatmentIsOK )
     
        this.isOK();  ==> Your code
     
     else
     
        this.isOK();  ==> Your code
     

.......

【讨论】:

这是@Hans 在对该问题的第一条评论中所说的。使用CancelEventArgs 可以轻松完成,不是吗?为什么不使用CancelEventArgs 当然!!你可以使用它。我的解决方案提供了更精细地自定义 EventArgs 的可能性。 仅供以后使用。 CancelEventArgs 是一个很好的解决方案 很好,我不知道您可以在触发事件后检查自定义 eventArg 成员的值。 (我已经在使用自定义事件处理程序,我没有将它放在示例中,因为我认为它只是分散了手头的主题,显然不是)。谢谢,我刚刚实现了您的想法,在编写其他部分之后我将能够对其进行真正的测试,但我现在仍将其标记为解决方案 =)【参考方案3】:

为什么不创建自己的 EventArgs 类并将 B 放入其中?

喜欢:

public class ClassBEventArgs : EventArgs

    public classB classBObject  get; set; 

【讨论】:

以上是关于在订阅了另一个对象的事件的委托中使用 (object sender)的主要内容,如果未能解决你的问题,请参考以下文章

C#里事件和委托有啥区别啊??

事件与委托

订阅/取消订阅列表中的事件[重复]

C# 委托和事件 与 观察者模式(发布-订阅模式)讲解 by天命

第14章 事件

通过匿名委托取消订阅事件[重复]