2016-04-21 53 views
2

有沒有一種巧妙的方式來獲得在「開始」函數中工作的類型推斷,而無需在Pipe類上定義泛型?聰明的方式來獲得類型推斷?

藉助開始會是這個樣子:

Pipe.Start<ToUpper, string, string>(... 

我想它是

Pipe.Start(... 

與用例的完整代碼將在下面進行顯示:

using System; 
using System.Threading.Tasks; 

namespace Code 
{ 
    public class Pipe 
    { 
    private Func<object, Task> next; 

    public static Section<TOut> Start<TStep, TIn, TOut>(Func<TStep> func, Func<TStep, TIn, TOut> runFunc) 
    { 
     var pipeline = new Pipe(); 
     var nextPipe = new Section<TIn>(pipeline); 

     pipeline.next = o => nextPipe.Run((TIn)o); 

     return nextPipe.Then(func, runFunc); 
    } 

    public async Task Run<TIn>(TIn start) 
    { 
     await next(start); 
    } 

    public class Section<TIn> 
    { 
     public Pipe Pipe { get; } 

     private Func<TIn, Task> next; 

     internal Section(Pipe pipe) 
     { 
      Pipe = pipe; 
     } 

     public async Task Run(Task<TIn> start) 
     { 
      if (next != null) await next(await start); 
     } 

     public async Task Run(TIn start) 
     { 
      if (next != null) await next(start); 
     } 

     public Section<TOut> Then<TStep, TOut>(Func<TStep> func, Func<TStep, TIn, TOut> filter) 
     { 
      var pipeLineStep = new Section<TOut>(Pipe); 
      next = @in => pipeLineStep.Run(Task.FromResult(filter(func(), @in))); 
      return pipeLineStep; 
     } 

     public Section<TOut> Then<TStep, TOut>(Func<TStep> func, Func<TStep, TIn, Task<TOut>> runFunc) 
     { 
      var pipeLineStep = new Section<TOut>(Pipe); 
      next = @in => pipeLineStep.Run(runFunc(func(), @in)); 
      return pipeLineStep; 
     } 
    } 
} 
} 

測試

using System.Linq; 
using System.Threading.Tasks; 
using FluentAssertions; 
using Code; 
using Xunit; 

namespace Test 
{ 
public class PipeTets 
{ 
    [Fact] 
    public async void FactMethodName() 
    { 
     var toUpper = new ToUpper(); 
     var toReverse = new ToReverse(); 
     var toLower = new ToLower(); 
     var toLength = new ToLength(); 
     var toDouble = new ToDouble(); 

     await Pipe.Start<ToUpper, string, string>(() => toUpper, (upper, s) => upper.Run(s)) 
        .Then(() => toReverse, (reverse, s) => reverse.Run(s)) 
        .Then(() => toLower, (lower, s) => lower.Run(s)) 
        .Then(() => toLength, (length, s) => length.Run(s)) 
        .Then(() => toDouble, (@double, i) => @double.Run(i)) 
        .Pipe 
        .Run("lower"); 


     toUpper.Upper.Should().Be("LOWER"); 
     toReverse.Reverse.Should().Be("REWOL"); 
     toLower.Lower.Should().Be("rewol"); 
     toLength.Length.Should().Be(5); 
     toDouble.Double.Should().Be(10); 
    } 
} 

public class ToReverse 
{ 
    public string Reverse; 

    public string Run(string text) 
    { 
     Reverse = new string(text.Reverse().ToArray()); 
     return Reverse; 
    } 
} 

public class ToUpper 
{ 
    public string Upper; 

    public string Run(string text) 
    { 
     Upper = text.ToUpper(); 
     return Upper; 
    } 
} 

public class ToLower 
{ 
    public string Lower; 

    public Task<string> Run(string text) 
    { 
     Lower = text.ToLower(); 
     return Task.FromResult(Lower); 
    } 
} 

public class ToLength 
{ 
    public int Length; 

    public Task<int> Run(string text) 
    { 
     Length = text.Length; 
     return Task.FromResult(Length); 
    } 
} 

public class ToDouble 
{ 
    public int Double; 

    public Task<int> Run(int text) 
    { 
     Double = text * 2; 
     return Task.FromResult(Double); 
    } 
} 
} 
+0

這豈不是更有用的API,如果你的管道接受泛型集合?這也可能解決類型推斷問題。 –

+0

通用的操作集合?這不會允許TIn和TOUT對於不同的操作有所不同嗎? – Lejdholt

回答

0

只是明確定義的參數類型:

await Pipe.Start(() => toUpper, (ToUpper upper, string s) => upper.Run(s)) 
+0

這很有效。我要買它。 – Lejdholt