问题描述
我正在使用流利的语法构建个人自动化框架。这是管道示例
var pipeline = Core.Runner.CreatePipeline()
.BeginMany(Sources.Csv(@"..."))
.ThenTransform<dynamic,string[]>(record=> record.id.Split(":"))
.ThenTransform<string[],(string,string)>(record => (record[0],record[1]))
.ThenTransform<(string,string),dynamic>(new {...})
我想知道有什么方法可以提高可用性,并自动为链中的下一个TInput
设置TOutput
等于ThenTransform<TInput,TOutput>
并在构建时验证类型吗?
期望的结果
var pipeline = Core.Runner.CreatePipeline()
.BeginMany(Sources.Csv(@"..."))
.ThenTransform<string[]>(record=> record.id.Split(":")) // TInput is dynamic,TOutput is string[]
.ThenTransform<(string,record[1])) // TInput is string[],TOuput is (string,string)
.ThenTransform<dynamic>(new {...}) // etc
由于lambda知道返回类型,因此可能会有更好的结果
var pipeline = Core.Runner.CreatePipeline()
.BeginMany(Sources.Csv(@"..."))
.ThenTransform(record=> record.id.Split(":")) // TInput is dynamic,TOutput is string[]
.ThenTransform(record => (record[0],string)
.ThenTransform(new {...}) // etc
解决方法
您尚未在此处指定如何存储状态,但是对于泛型,您可以执行以下操作:
using System;
namespace ConsoleApp16
{
class Program
{
static void Main(string[] args)
{
var pipeline = Core.Runner.CreatePipeline<dynamic>()
.BeginMany(Sources.Csv(@"..."))
// Type cannot be inferred from dynamic
.ThenTransform<string[]>(record => record.id.Split(":"))
.ThenTransform(record => (record[0],record[1]))
.ThenTransform(s => s.Item1);
}
}
internal class Sources
{
public static object Csv(string s)
{
return new object();
}
}
internal class Core
{
public class Runner
{
public static Pipeline<TInput> CreatePipeline<TInput>()
{
return new Pipeline<TInput>(new PipelineState());
}
}
}
internal class PipelineState
{
public bool MyState { get; set; }
}
internal class Pipeline<TInput>
{
private readonly PipelineState _pipelineState;
public Pipeline(PipelineState pipelineState)
{
_pipelineState = pipelineState;
}
public Pipeline<TInput> BeginMany(object csv)
{
// Update state
return this;
}
public Pipeline<TOutput> ThenTransform<TOutput>(Func<TInput,TOutput> func)
{
// Update state
return new Pipeline<TOutput>(_pipelineState);
}
}
}
您可以通过使用不同方法返回的不同PipelineBuilder
类来对此进行改进。例如,BeginMany
可能返回一个具有ThenTransform
方法的类,以便强制执行该顺序:
using System;
namespace ConsoleApp16
{
class Program
{
static void Main(string[] args)
{
var pipeline = Core.Runner.CreatePipeline()
.BeginMany(Sources.Csv(@"..."))
// Type cannot be inferred from dynamic
.ThenTransform<string[]>(record => record.id.Split(":"))
.ThenTransform(record => (record[0],record[1]))
.ThenTransform(s => s.Item1)
.Build();
}
}
internal class Sources
{
public static Source<dynamic> Csv(string s)
{
return new Source<dynamic>();
}
}
internal class Source<T>
{
}
internal class Core
{
public class Runner
{
public static PipelineBuilder CreatePipeline()
{
return new PipelineBuilder(new PipelineState());
}
}
}
internal class PipelineState
{
public bool MyState { get; set; }
}
internal class PipelineBuilder
{
protected readonly PipelineState State;
public PipelineBuilder(PipelineState state)
{
State = state;
}
public PipelineBuilder<TInput> BeginMany<TInput>(Source<TInput> source)
{
// Update state
return new PipelineBuilder<TInput>(State);
}
public Pipeline Build()
{
// Populate from state
return new Pipeline();
}
}
internal class PipelineBuilder<TInput> : PipelineBuilder
{
public PipelineBuilder(PipelineState pipelineState) : base(pipelineState)
{
}
public PipelineBuilder<TOutput> ThenTransform<TOutput>(Func<TInput,TOutput> func)
{
// Update state
return new PipelineBuilder<TOutput>(State);
}
}
internal class Pipeline
{
}
}
值得研究构建器模式,当与接口和扩展方法结合使用时,它可能会非常强大。一个很好的例子是Microsoft.Extensions.Configuration
https://github.com/dotnet/extensions/tree/release/3.1/src/Configuration