Created
December 20, 2013 14:17
-
-
Save Novakov/8055374 to your computer and use it in GitHub Desktop.
C# pipeline written using | operator - like command line
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace PipelineOperators | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var toLower = new LambdaPipelineItem<string, string>(x => x.ToLower()); | |
var replace = new LambdaPipelineItem<string, string>(x => x.Replace("A", "AA")); | |
var length = new LambdaPipelineItem<string, int>(x => x.Length); | |
var input = "ABCD"; | |
var output = input | replace | toLower | length; | |
Console.WriteLine(output.Value); | |
var o = Pipeline<string>.Of(x => x | replace | toLower | length); | |
Console.WriteLine(o.Run("ABCD")); | |
Console.WriteLine(o.Run("1234567")); | |
} | |
} | |
public class Carried<T> | |
{ | |
private readonly T value; | |
public T Value { get { return this.value; } } | |
public Carried(T value) | |
{ | |
this.value = value; | |
} | |
public static implicit operator Carried<T>(T value) | |
{ | |
return new Carried<T>(value); | |
} | |
} | |
public abstract class PipelineItem<TInput, TOutput> :IPipelineItem | |
{ | |
public abstract TOutput Run(TInput input); | |
public static Carried<TOutput> operator |(Carried<TInput> input, PipelineItem<TInput, TOutput> pipelineItem) | |
{ | |
return pipelineItem.Run(input.Value); | |
} | |
object IPipelineItem.Run(object input) | |
{ | |
return this.Run((TInput) input); | |
} | |
} | |
internal interface IPipelineItem | |
{ | |
object Run(object input); | |
} | |
public class LambdaPipelineItem<TInput, TOutput> : PipelineItem<TInput, TOutput> | |
{ | |
private readonly Func<TInput, TOutput> action; | |
public LambdaPipelineItem(Func<TInput, TOutput> action) | |
{ | |
this.action = action; | |
} | |
public override TOutput Run(TInput input) | |
{ | |
return this.action(input); | |
} | |
} | |
public static class Pipeline<TInput> | |
{ | |
public static Pipeline<TInput, TOutput> Of<TOutput>(Expression<Func<Carried<TInput>, Carried<TOutput>>> pipeline) | |
{ | |
var decomposed = DecomposeOr((BinaryExpression) pipeline.Body).Skip(1); | |
var items = decomposed.Select(ExtractItem).ToList(); | |
return new Pipeline<TInput, TOutput>(items); | |
} | |
private static IPipelineItem ExtractItem(Expression arg) | |
{ | |
return Expression.Lambda<Func<IPipelineItem>>(arg).Compile().Invoke(); | |
} | |
private static IEnumerable<Expression> DecomposeOr(BinaryExpression expression) | |
{ | |
if (expression.Left.NodeType == ExpressionType.Or) | |
{ | |
foreach (var right in DecomposeOr((BinaryExpression)expression.Left)) | |
{ | |
yield return right; | |
} | |
} | |
else | |
{ | |
yield return expression.Left; | |
} | |
yield return expression.Right; | |
} | |
} | |
public class Pipeline<TInput, TOutput> | |
{ | |
private readonly List<IPipelineItem> items; | |
internal Pipeline(List<IPipelineItem> items) | |
{ | |
this.items = items; | |
} | |
public TOutput Run(TInput input) | |
{ | |
return (TOutput) this.items.Aggregate((object)input, (acc, item) => item.Run(acc)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment