C# 获得类型推断的聪明方法?

C# 获得类型推断的聪明方法?,c#,generics,inferred-type,C#,Generics,Inferred Type,有没有一种聪明的方法可以让类型推断在“Start”函数中工作,而不用在管道类上定义泛型类型 使用“开始”类似于以下内容: Pipe.Start<ToUpper, string, string>(... 带有用例的完整代码如下所示: using System; using System.Threading.Tasks; namespace Code { public class Pipe { private Func<object, Task>

有没有一种聪明的方法可以让类型推断在“Start”函数中工作,而不用在管道类上定义泛型类型

使用“开始”类似于以下内容:

Pipe.Start<ToUpper, string, string>(...
带有用例的完整代码如下所示:

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;
        }
    }
}
}
使用系统;
使用System.Threading.Tasks;
名称空间代码
{
公共级管道
{
私人Func next;
公共静态节开始(Func Func,Func runFunc)
{
var pipeline=新管道();
var nextPipe=新段(管道);
pipeline.next=o=>nextPipe.Run((TIn)o);
返回下一个管道。然后(func,runFunc);
}
公共异步任务运行(TIn启动)
{
等待下一步(开始);
}
公共课组
{
公共管道{get;}
私人Func next;
内部截面(管道)
{
管道=管道;
}
公共异步任务运行(任务启动)
{
如果(下一步!=null)等待下一步(等待启动);
}
公共异步任务运行(TIn启动)
{
如果(下一步!=null)等待下一步(开始);
}
公共部分(Func Func,Func filter)
{
var pipeLineStep=新截面(管道);
next=@in=>pipeLineStep.Run(Task.FromResult(filter(func(),@in));
返回管道步骤;
}
公共部分(Func Func,Func runFunc)
{
var pipeLineStep=新截面(管道);
next=@in=>pipeLineStep.Run(runFunc(func(),@in));
返回管道步骤;
}
}
}
}
试验

使用System.Linq;
使用System.Threading.Tasks;
使用FluentAssertions;
使用代码;
使用Xunit;
名称空间测试
{
公共级管道
{
[事实]
公共异步void FactMethodName()
{
var toUpper=新toUpper();
var toReverse=新的toReverse();
var-toLower=新的toLower();
var toLength=新的toLength();
var toDouble=新toDouble();
等待管道开始(()=>toUpper,(上,s)=>upper.Run)
.然后(()=>toReverse,(reverse,s)=>reverse.Run)
。然后(()=>toLower,(lower,s)=>lower.Run)
.然后(()=>toLength,(length,s)=>length.Run)
然后(()=>toDouble,(@double,i)=>@double.Run(i))
管
.运行(“较低”);
toUpper.Upper.Should()应该是(“LOWER”);
toReverse.Reverse.Should().Be(“REWOL”);
toLower.Lower.Should()应为“rewol”;
toLength.Length.应()为(5);
toDouble.Double.Should()为(10);
}
}
公共类反向
{
公共字符串反转;
公共字符串运行(字符串文本)
{
Reverse=新字符串(text.Reverse().ToArray());
反向返回;
}
}
公共类投机者
{
公共字符串上限;
公共字符串运行(字符串文本)
{
上限=text.ToUpper();
返回上;
}
}
公共舱
{
公共字符串较低;
公共任务运行(字符串文本)
{
Lower=text.ToLower();
返回任务.FromResult(较低);
}
}
公共类长度
{
公共整数长度;
公共任务运行(字符串文本)
{
长度=文本长度;
返回任务.FromResult(长度);
}
}
公共课加倍
{
公共整数双精度;
公共任务运行(整型文本)
{
Double=文本*2;
返回任务.FromResult(双精度);
}
}
}

只需明确定义参数类型:

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

如果您的管道接受通用集合,那么这不是一个更有用的API吗?这也可能解决类型推断问题。操作的通用集合?这不会让锡和兜售因不同的行为而有所不同,对吗?
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);
    }
}
}
await Pipe.Start(() => toUpper, (ToUpper upper, string s) => upper.Run(s))