views:

57

answers:

1

I'm trying to do a simple implementation of the Specification pattern in my domain layer.

If I have a static class full of specifications like this:

public static class FooSpecifications
{
  public static Func<Foo, bool> IsSuperhuman
  {
    get
    {
      return foo => foo.CanShootLasersOutOfItsEyes && foo.CanFly;
    }
  }
}

Then I can do marvellous things like this:

IEnumerable<Foo> foos = GetAllMyFoos();
var superFoos = foos.Where(FooSpecifications.IsSuperhuman);

I can also add bool method to Foo to determine if a particular instance meets a specification:

public bool Meets(Func<Foo, bool> specification)
{
  return specification.Invoke(this);
}

Given that Foo, like all my domain entities, extends DomainObject, is there a way I can put a generic implementation of Meets() into the DomainObject to save me implementing Meets() separately in every entity?

A: 

Something like this...

    public abstract class DomainObj<T> // T - derived type
        where T : DomainObj<T>
    {
        public bool Meets(Func<T, bool> specification)
        {
            return specification.Invoke((T) this);
        }
    }

    public class Foo : DomainObj<Foo> {}

    public class Bar : DomainObj<Bar> {}       

        Func<Foo, bool> foospec = x => true;
        Func<Bar, bool> barspec = x => true;

        var foo = new Foo();
        var bar = new Bar();
        foo.Meets(foospec);
        foo.Meets(barspec); // won't compile because of mismatched types of spec and object instance

EDIT

Maybe it will be better to translate Meet method to extension. This will remove need in type parameter.

    public abstract class DomainObj
    {
    }

    public static class DomainObjExtensions
    {
        public static bool Meets<T>(this T obj, Func<T, bool> f)
            where T : DomainObj
        {
            return f(obj);
        }
    }

    public class Foo : DomainObj {}

    public class Bar : DomainObj {}

    Func<Foo, bool> foospec = x => true;
    Func<Bar, bool> barspec = x => true;

    var foo = new Foo();
    var bar = new Bar();
    foo.Meets(foospec);
    foo.Meets(barspec); // error
desco
What are the braces after the derived class declarations? When I put them in, I start getting 'namespace cannot contain members' compiler errors.
David
Either way, in the derived class the compiler doesn't recognise the DomainObject type, even though they're in the same namespace.
David
My bad: I had pasted some of your code but not noticed you were using DomainObj instead of DomainObject.
David
This appears to work but now I have another problem. How do I cast a derived type back to DomainObject<T>?
David
Sorry, I don't mean cast derived type to DomainObject, rather cast an object to DomainObject.
David
The extension method clinched it, thanks.
David