Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 876
David Avatar asked May 12 '10 10:05

David


3 Answers

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 :(

like image 96
Artiom Chilaru Avatar answered Oct 01 '22 11:10

Artiom Chilaru


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.

like image 27
Jordão Avatar answered Oct 01 '22 13:10

Jordão


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.

like image 37
Bob Sammers Avatar answered Oct 01 '22 12:10

Bob Sammers