当前位置:  开发笔记 > 编程语言 > 正文

C#中的管道转发

如何解决《C#中的管道转发》经验,为你挑选了1个好方法。

继续我在C#中表达F#想法的调查,我想要一个管道前进算子.对于包含在IEnumerable中的任何东西,我们已经拥有它,因为你可以.NextFunc()到你心中的内容.但是,例如,如果最后有任何类似折叠的缩减,则无法将其结果输入函数.

这里有两种扩展方法,我想知道是否有其他人试过这个,如果这是个好主意(编辑:现在有了Earwicker的可能包括在内):

public static void Pipe(this T val, Action action) where T : class
{ if (val!=null) action(val); }

public static R Pipe(this T val, Func func) where T : class where R : class
{ return val!=null?func(val):null; }

然后你可以写下这样的东西:

Func readlines = (f) => File.ReadAllLines(f);
Action writefile = (f, s) => File.WriteAllText(f, s);

Action RemoveLinesContaining = (file, text) =>
    {
        file.Pipe(readlines)
            .Filter(s => !s.Contains(text))
            .Fold((val, sb) => sb.AppendLine(val), new StringBuilder())
            .Pipe((o) => o.ToString())
            .Pipe((s) => writefile(file, s));
    };

(我知道,过滤器==在C#中的位置,并且折叠==聚合,但我想要自己动手,我本可以完成WriteAllLines,但这不是重点)

编辑:根据Earwicker的评论进行更正(如果我理解正确的话).



1> Daniel Earwi..:

我没有使用原始管道,但我尝试将所有引用都引入到Maybe monad中:

public static class ReferenceExtensions
{
    public static TOut IfNotNull(this TIn v, Func f)
                                    where TIn : class 
                                    where TOut: class
    {
        if (v == null)
            return null;

        return f(v);
    }
}

然后假设您有一个对象模型,它允许您按名称查找RecordCompany,然后在该RecordCompany中查找Band,Band的成员,并且其中任何一个都可能返回null,因此这可能会抛出NullReferenceException:

var pixiesDrummer = Music.GetCompany("4ad.com")
                         .GetBand("Pixes")
                         .GetMember("David");

我们可以解决这个问题

var pixiesDrummer = Music.GetCompany("4ad.com")
                         .IfNotNull(rc => rc.GetBand("Pixes"))
                         .IfNotNull(band => band.GetMember("David"));

嘿presto,如果这些转换中的任何一个返回null,pixiesDrummer将为null.

如果我们能够做出运算符重载的扩展方法,那不是很好吗?

public static TOut operator| (TIn v, Func f)

然后我可以像这样把我的过渡lambdas连在一起:

var pixiesDrummer = Music.GetCompany("4ad.com")     
                     | rc => rc.GetBand("Pixes")
                     | band => band.GetMember("David");

如果System.Void被定义为一个类型并且Action真的只是Func <...,Void>,那也不是很好吗?

更新: 我在博客上写了一下这背后的理论.

更新2:原始问题的另一种答案,大致是"你如何在C#中表达F#管道转发运算符?"

管道输送是:

let (|>) x f = f x

换句话说,它允许您以相反的顺序编写函数及其第一个参数:参数后跟函数.它只是一个语法助手,有助于提高可读性,允许您使用任何函数的中缀表示法.

这正是C#中的扩展方法.没有它们,我们必须写:

var n = Enumerable.Select(numbers, m => m * 2);

有了它们,我们可以写:

var n = numbers.Select(m => m * 2);

(忽略这样一个事实,即他们也让我们省略了类名 - 这是一个奖励,但也可以用于非扩展方法,就像在Java中一样).

所以C#已经以不同的方式解决了同样的问题.


回到这个6年后,我希望有两件事:能够调用没有类名前缀的静态方法(在Rosyln/C#6中)和通过扩展方法重载运算符的能力(结果非常好)很容易添加到Roslyn:https://smellegantcode.wordpress.com/2014/04/24/adventures-in-roslyn-adding-crazily-powerful-operator-overloading-to-c-6/)
推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有