Fluent API extensions

Every custom Specification can be "plugged-in" to Fluent API. Special extensions are needed for this. We will use ExpiredCreditCardSpecification from previous example.

public static IComplexSpecification<CreditCard> ExpiredCreditCard(this ICompositeSpecification<CreditCard> self)
{
    return self.Compose(new ExpiredCreditCardSpecification());
}

public static IComplexSpecification<CreditCard> NotExpiredCreditCard(this ICompositeSpecification<CreditCard> self)
{
    return self.Compose(new ExpiredCreditCardSpecification().Not());
}

var creditCardSpec1 = Specification
    .Null<CreditCard>()
    .Or()
    .ExpiredCreditCard();
var creditCardSpec2 = Specification
    .NotNull<CreditCard>()
    .And()
    .NotExpiredCreditCard();

ICompositeSpecification<T> interface represents FluentApi And, AndNot, Or, OrNot methods. Compose method create specific composite Specification.

Unfortunately Specification class is static, so custom specification cannot be created in this way right now.

Extensions for properties

If you intend to use CreditCard as property in other type, you can also provide extensions with property selectors.

public static IComplexSpecification<T> ExpiredCreditCard<T>(this ICompositeSpecification<T> self,
    Expression<Func<T, CreditCard>> selector)
{
    return self.Compose(Specification.ForProperty(selector,
        new ExpiredCreditCardSpecification()));
}

public static IComplexSpecification<T> NotExpiredCreditCard<T>(this ICompositeSpecification<T> self,
    Expression<Func<T, CreditCard>> selector)
{
    return self.Compose(Specification.ForProperty(selector,
        new ExpiredCreditCardSpecification().Not()));
}

var customerSpec1 = Specification
    .NotNull<Customer>()
    .And()
    .ExpiredCreditCard(c => c.CreditCard);
var customerSpec2 = Specification
    .Null<Customer>()
    .Or()
    .NotExpiredCreditCard(c => c.CreditCard);
GitHub