I truly enjoy working with Parallel Extensions Extras, but must admit, still find myself challenged when it comes to creating extensions for Fluent programming methods.
I have a particular need, given this simple BusinessEntity
following the Null Object Pattern
public abstract class BusinessEntity
{
public static readonly BusinessEntity Null = new NullBusinessEntity();
public long EntityKey { get; set; }
private class NullBusinessEntity : BusinessEntity
{
}
}
How would I go about creating a "conditional Next" step, which would execute the body of the function only if a condition was met?
For now this is what I do:
Func<BusinessEntity, Func<BusinessEntity,BusinessEntity>, BusinessEntity> conditional = (be, func) =>
{
if (be.Equals(BusinessEntity.Null)) return be;
return func.Invoke(be);
};
Then in the pipeline I invoke it like so:
Pipeline<BusinessEntity, string> pipeline = Pipeline.Create<BusinessEntity, BusinessEntity>(CheckEntity)
.Next<BusinessEntity>(be => conditional.Invoke(be, entity => ProcessEntity(be)))
.Next<string>(FinalResult);
Is there a way to create an Extension to the Pipeline, specific to my BusinessEntity
(or not), which would allow me to call it like this:
Pipeline<BusinessEntity, string> pipeline = Pipeline
.Create<BusinessEntity, BusinessEntity>(CheckEntity)
.ConditionalNext<BusinessEntity>(ProcessEntity)
.Next<string>(FinalResult);
Is that possible?
If you wanted to make a generic extension for this that's conditional on null
, you just need to write an extension method that invokes Next()
with your conditional
lambda like:
public static Pipeline<TInput, TNextOutput>
ConditionalNext<TInput, TOutput, TNextOutput>(
this Pipeline<TInput, TOutput> pipeline, Func<TOutput, TNextOutput> func)
where TOutput : class
where TNextOutput : class
{
return pipeline.Next(x => x == null ? null : func(x));
}
The problem with the null object pattern is that it's not usable in generic methods, so you will have to make it specific to your type:
public static Pipeline<TInput, BusinessEntity> ConditionalNext<TInput>(
this Pipeline<TInput, BusinessEntity> pipeline,
Func<BusinessEntity, BusinessEntity> func)
{
return pipeline.Next(x => x.Equals(BusinessEntity.Null) ? x : func(x));
}
In both cases, the usage would look like this:
var pipeline = Pipeline.Create<BusinessEntity, BusinessEntity>(CheckEntity)
.ConditionalNext(ProcessEntity)
.Next(FinalResult);