Wednesday, August 01, 2007

Mixing Peer (extension objects in c# 2.0)

In project X we have a big hierarchy of objects/interfaces:
Eintrag
- Artikel
- NeuFormArtikel
- NormalArtikel
- AbdaArtikel
- Verweis
- AbrechnungsEintrag

(The hierarchy is bigger, but this is enough for our purpose.)
We have a case, where in a View we must display a union of fields from this hierarchy. i.e. AbdaArtikel.Preis if the object has such a property, otherwise null/string.Empty.

We have several options:
- use a visitor for the whole hierarchy
- use a PropertyMapper (reflection-fluent-interface-based machinery) (looks pretty slick, enables a very declarative way of mapping, maybe I will post about it)
- extend/pull the AbdaArtikelPreis into the Eintrag (if we need it there)
- mix in a generic visitor:

Since the objects/interfaces in the hierarchy are Nhibernate BOs, they are proxied, i.e., in our configuration, we cannot use generic methods in BOs. But we can extend the BO with an object which can:
  1. we define Eintrag.Peer() { return new EintragPeer( this ); }
  2. now we can extend the peer/mixing with generics

public class EintragPeer {

private readonly Eintrag _extended;

public EintragPeer( Eintrag extendable ) { _extended = extendable; }

public R TryMap(Func func, R otherwise_default) where T : Eintrag {

if ( _extended is T ) { return func( _extended as T ); }

return otherwise_default;

}

public void TryApply(Action action) where T : Eintrag {

if (_extended is T) { return action(_extended as T); }

}

}



  1. Now we can use it as:

Preis eintrag_preis = eintrag.Peer().TryMap(

delegate(Artikel artikel) { return artikel.Preis; },

Preis.Null);



Other variations can be build on that.

No comments: