C#:在单个语句中将对象中的所有事件连接起来

时间:2010-05-12 10:04:28

标签: c# events delegates

在我的域层中,所有域对象都会发出事件(类型为InvalidDomainObjectEventHandler),以指示调用IsValid属性时的无效状态。

在aspx代码隐藏中,我必须手动连接域对象的事件,如下所示:

_purchaseOrder.AmountIsNull += new DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent);
_purchaseOrder.NoReason += new DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent);
_purchaseOrder.NoSupplier += new DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent);
_purchaseOrder.BothNewAndExistingSupplier += new DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent);

请注意,在每种情况下都会调用相同的方法,因为InvalidDomainobjectEventArgs类包含要显示的消息。

有没有什么方法可以编写单个语句来一次性连接InvalidDomainObjectEventHandler类型的所有事件?

由于

大卫

5 个答案:

答案 0 :(得分:5)

我认为你不能在一个声明中做到这一点..但你可以使代码更容易读取:

_purchaseOrder.AmountIsNull += HandleDomainObjectEvent;
_purchaseOrder.NoReason += HandleDomainObjectEvent;
_purchaseOrder.NoSupplier += HandleDomainObjectEvent;
_purchaseOrder.BothNewAndExistingSupplier += HandleDomainObjectEvent;

除此之外 - 似乎答案是否定的:(

答案 1 :(得分:3)

您可以在某个基类(或某个帮助程序类中,或在PurchaseOrder类本身中创建聚合事件,如果您有权访问它):

abstract class BaseOrderPage : Page {

  PurchaseOrder _purchaseOrder = new PurchaseOrder();

  ...

  public event InvalidDomainObjectEventHandler InvalidDomainObjectEvent {
    add {
      _purchaseOrder.AmountIsNull += value;
      _purchaseOrder.NoReason += value;
      _purchaseOrder.NoSupplier += value;
      _purchaseOrder.BothNewAndExistingSupplier += value;
    }
    remove {
      _purchaseOrder.AmountIsNull -= value;
      _purchaseOrder.NoReason -= value;
      _purchaseOrder.NoSupplier -= value;
      _purchaseOrder.BothNewAndExistingSupplier -= value;
    }
  }

}

然后在派生类中使用它:

    InvalidDomainObjectEvent += new DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent);

C#2.0及以上:

    InvalidDomainObjectEvent += HandleDomainObjectEvent;

我已成功使用此技术聚合events of the FileSystemWatcher类。

答案 2 :(得分:2)

您可以使用反射自动执行此操作。我想你想要这样的东西:

public static void WireEvents(object subject)
{
    Type type = subject.GetType();

    var events = type.GetEvents()
        .Where(item => item.EventHandlerType == typeof(InvalidDomainObjectEventHandler));

    foreach (EventInfo info in events)
        info.AddEventHandler(subject, new InvalidDomainObjectEventHandler(HandleDomainObjectEvent));
}

然后,在创建新对象时所要做的就是:

PurchaseOrder _purchaseOrder = new PurchaseOrder();
HelperClass.WireEvents(_purchaseOrder);

不要忘记,如果您创建PurchaseOrder和其他类似对象,那么反射会对性能造成影响。

编辑 - 其他说明:您需要using System.Reflection指令。就目前而言,此代码需要var关键字的C#3和Where()方法的.net框架3.5(如果它不是自动生成的,则需要using System.Linq;)。

正如David在稍后的回答中所做的那样,可以在不更改早期版本的基本功能的情况下重写它。

答案 3 :(得分:0)

您可以考虑将事件处理程序放入接口。然后你附上界面:

public interface IPurchaseOrderObserver
{
    void AmountIsNullEventHandler(WhateverArgs);
    void NoReasonEventHandler(WhateverArgs);
    void NoSupplierEventHandler(WhateverArgs);
    void BothNewAndExistingSupplierEventHandler(WhateverArgs);
}

_purchaseOrder.RegisterObserver(DomainObject);

您可以将这四行放入RegisterObeserver方法,或者替换事件并直接调用接口。

答案 4 :(得分:0)

我看了Bob Sammers的建议。编译器不喜欢GetEvents()返回的EventInfo []的.Where方法,但是我将代码略微更改为以下内容:

private void HookUpEvents()
{
  Type purchaseOrderType = typeof (PurchaseOrder);
  var events = purchaseOrderType.GetEvents();
  foreach (EventInfo info in events)
  {
    if (info.EventHandlerType == typeof(Kctc.Data.Domain.DomainObject.InvalidDomainObjectEventHandler))
    {
      info.AddEventHandler(_purchaseOrder, new Kctc.Data.Domain.DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent));
    }
  }
}

在我将这个方法添加到页面之后,这一切都非常适合hunky dory。我可以将事件添加到采购订单对象中,而不必记住将它们单独连接起来,这正是我想要的。