开发者

C#: Hook up all events from object in single statement

开发者 https://www.devze.com 2022-12-29 20:34 出处:网络
In my domain layer all domain objects emit events (of type InvalidDomainObjectEventHandler) to indicate invalid state when 开发者_开发知识库the IsValid property is called.

In my domain layer all domain objects emit events (of type InvalidDomainObjectEventHandler) to indicate invalid state when 开发者_开发知识库the IsValid property is called.

On an aspx codebehind, I have to manually wire up the events for the domain object like this:

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

Note that the same method is called in each case since the InvalidDomainobjectEventArgs class contains the message to display.

Is there any way I can write a single statement to wire up all events of type InvalidDomainObjectEventHandler in one go?

Thanks

David


I don't think you can do this in a single statement.. But you can make the code more readible like this:

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

Other than that - seems like the answer's no :(


You can create an aggregate event in some base class (or in some helper class, or in the PurchaseOrder class itself, if you have access to it):

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;
    }
  }

}

And then just use it in the derived classes:

    InvalidDomainObjectEvent += new DomainObject.InvalidDomainObjectEventHandler(HandleDomainObjectEvent);

C# 2.0 and above:

    InvalidDomainObjectEvent += HandleDomainObjectEvent;

I've used this technique successfully to aggregate events of the FileSystemWatcher class.


You can use reflection to do this automatically. I think you want something like this:

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));
}

Then, all you have to do when you create a new object is this:

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

Don't forget that there is a performance penalty with reflection that will be apparent if you create PurchaseOrders and other similar objects in any great numbers.

Edit - other notes: you will need a using System.Reflection directive. As it stands, this code needs C#3 for the var keyword and .net framework 3.5 for the Where() method (and - if it's not automatically generated - using System.Linq;).

As David has done in a later answer, it can be re-written without changing the basic functionality for earlier versions.


I looked at Bob Sammers' suggestion. The compiler wasn't liking the .Where method of the EventInfo[] returned by GetEvents(), but I've changed the code slightly to the following:

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));
    }
  }
}

After I added this method to the page, it all worked absolutely hunky dory. And I can add events to the purchase order object without having to remember to hook them up individually, which is exactly what I wanted.


You could consider to put the event handlers into an interface. Then you attach the interface:

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

_purchaseOrder.RegisterObserver(DomainObject);

You either put this four lines into the RegisterObeserver method, or you replace the events and directly call the interfaces.

0

精彩评论

暂无评论...
验证码 换一张
取 消