当前位置: 首页 > 编程笔记 >

C#函数式编程中的部分应用详解

柏明亮
2023-03-14
本文向大家介绍C#函数式编程中的部分应用详解,包括了C#函数式编程中的部分应用详解的使用技巧和注意事项,需要的朋友参考一下

何谓函数式编程

相信大家在实际的开发中,很多情况下完成一个功能都需要借助多个类,那么我们这里的基本单元就是类。而函数式编程则更加细化,致使我们解决一个功能的基本单元是函数,而不是类,每个功能都是由多个函数构成,并且函数之间没有直接的关系。如果简单的文字描述还不足以让你理解,下面我们就配以图来演示。

如下图所示,图左是我们设计好的三个函数,而右边则是我们需要实现的功能。而我们需要做的就是利用这三个函数去完成对应的三个功能,笔者在这里只是进行简单而又形象的表述,实际的开发过程可能需要更多的函数,并且需要使用不同的函数式编程的方式组合才能完成对应的功能。

后面我们假设F1和F2进行组合可以完成功能G1,那么结果就如下图所示:

对应的其他功能我们依然是按照上面的方式进行组合就可以完成对应的功能,这样做必然有其对应的优点,对笔者而言最大的优点就是函数不受外部环境的影响,这里我们不能与类中的方法相提并论,因为方法会受到类上下文变量的影响,特别是在多线程的情况下会出现共享读和写的问题,而函数则不会,因为他只是通过参数的方式接收外部的变量,还有一点就是复用性很强,如果前期设计的充分,在后期开发过程中函数可以发挥到最大的作用。说了这么多废话,下面我们就可以开始我们的函数式编程的第一部分——部分应用。

部分应用

各位不用被这个名词吓坏,他主要是将我们多个参数的函数进行拆分,拆成多个只有一个参数的函数,比如下面这个函数,我们正常写的话都是这样写的:


Func<int, int, int> Add = (x, y) => x + y;

怎么调用相信笔者就不需要过多介绍了,下面我们就要让他能够支持部分应用:


Func<int, Func<int, int>> Add = x => y => x + y;

这下就应该明白了吧,只是在接收了一个值之后返回了下一个函数,然后我们再调用这个返回的函数就完成整个调用,我们是不是部分使用了这个函数?所以叫部分应用。下面我们来看看怎么使用这个函数:


var Add2 = Add(2);

var result = Add2(4);

这样分成两行比较容易看懂,但是我们可以仅仅使用一行就可以了,比如下面这个方式:


var result = Add(2)(5);

哇,是不是瞬间感觉高大上了,如果我们这个方法的参数再多点,就是括号加括号,相信别人看到你这行代码后就会呵呵了,然后心里一万个“某某”马奔腾。

我去,看到这的人会可能会吹嘘这又没有什么太特别的东西,就是函数返回函数。对就是函数返回函数,但是实际运用起来你就会发现舒畅多了,下面笔者简单的举一个比较靠谱的例子来说明部分应用能够带给我们什么,比如我们经常需要执行SQL语句,当然需要使用SqlConnection,然后附加上对应的SQL语句,为此我们可以开发一个简单的函数,用来简化这一过程:


Func<SqlConnection, Func<String, DataSet>> ExecSql = x => y =>

                    {

                        using (x)

                        {

                            x.Open();

                            var com = x.CreateCommand();

                            DataSet ds = new DataSet();

                            com.CommandText = y;

                            SqlDataAdapter adapter = new SqlDataAdapter(com);

                            adapter.Fill(ds);

                            return ds;

                        }

                    };

然后调用起来就简单多了,我们只要传递给对应的SqlConnection对象,然后对应的返回值我们就可以用来执行我们的SQL语句了,具体的使用示例如下所示:


var esql = ExecSql(new SqlConnection("xxx"));

var rds = esql("select xxxx from xxx");

rds = esql("select ffff from ffff");

但是做到这还没有结束,面对那些总是想出奇怪问题的人,我们还有一个需要做,就是我们可能先要传递SQL语句,然后再传递对应的SqlConnection对象,没问题,我们专门为此写个函数:


Func<String, Func<SqlConnection, DataSet>> ExecSqlT = x => y => ExecSql(y)(x);

我们就继续该怎么调用就调用吧,但是上面都是从一开始就利用部分应用的方式来写,实际情况可能是已经写好的普通的方式,需要转换成部分应用的方式。那么下面我们可以自己先手动的写几个扩展,以便于以后的使用,首先我们来写存在两个参数和返回值的扩展:


public static class Functional

    {

        public static Func<T1, Func<T2, T3>> Currey<T1, T2, T3>(this Func<T1, T2, T3> func)

        {

            return x => y => func(x, y);

        }

}

有了这个扩展之后我们再把上面的例子改写:


var ExecSql = Functional.Currey<SqlConnection, String, DataSet>((x, y) =>

                    {

                        using (x)

                        {

                            x.Open();

                            var com = x.CreateCommand();

                            DataSet ds = new DataSet();

                            com.CommandText = y;

                            SqlDataAdapter adapter = new SqlDataAdapter(com);

                            adapter.Fill(ds);

                            return ds;

                        }

                    });

这样我们就可以按照我们正常的形式来写,然后调用Functional的Currey就可以了,当然这里需要显示的传递泛型参数,有些情况下则不需要。

如果需要扩展更多参数的可以对应的写下去就可以了。当然上面仅仅只是针对没有参数的情况,我们也可以对Action也进行扩展:


public static Func<T1, Action<T2>> Currey<T1, T2>(this Action<T1, T2> func)

{

    return x => y => func(x, y);

}

到此我们就解决了将普通函数转换成部分应用方式的函数,但是问题就来了。如果我们一开始写的是部分应用方式的函数,怎么将其转换成普通的函数呢?自然我们还需要下面的扩展能够将其转换回去:


public static Func<T1, T2, T3> UnCurrey<T1, T2, T3>(this Func<T1, Func<T2, T3>> func)

{

    return (x, y) => func(x)(y);

}

 类似资料:
  • 本文向大家介绍C#函数式编程中的标准高阶函数详解,包括了C#函数式编程中的标准高阶函数详解的使用技巧和注意事项,需要的朋友参考一下 何为高阶函数       大家可能对这个名词并不熟悉,但是这个名词所表达的事物却是我们经常使用到的。只要我们的函数的参数能够接收函数,或者函数能够返回函数,当然动态生成的也包括在内。那么我们就将这类函数叫做高阶函数。但是今天我们的标题并不是高阶函数,而是标准高阶函数,

  • 本文向大家介绍C#函数式编程中的惰性求值详解,包括了C#函数式编程中的惰性求值详解的使用技巧和注意事项,需要的朋友参考一下 惰性求值       在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术。首先需要说明的是C#语言小部分采用了非严格求值策略,大部分还是严格求值策略。首先我们先演示非严格求值策略的情况,我们先在

  • 本文向大家介绍C#函数式编程中的缓存技术详解,包括了C#函数式编程中的缓存技术详解的使用技巧和注意事项,需要的朋友参考一下 缓存技术       该节我们将分成两部分来讲解,第一部分为预计算,第二部分则为缓存。缓存这个技术对应从事开发的人员来说是非常熟悉的,从页面缓存到数据库缓存无处不在,而其最重要的特点就是在第一次查询后将数据缓存,在以后的查询过程中就无需重新计算而直接从内存中将结果返回,大大提

  • 本文向大家介绍Swift的函数式编程详解,包括了Swift的函数式编程详解的使用技巧和注意事项,需要的朋友参考一下 Swift 相比原先的 Objective-C 最重要的优点之一,就是对函数式编程提供了更好的支持。 Swift 提供了更多的语法和一些新特性来增强函数式编程的能力,本文就在这方面进行一些讨论。 Swift 概览 对编程语言有了一些经验的程序员,尤其是那些对多种不同类型的编程语言都有

  • 函数式编程 -> 函数响应式编程 现在大家已经了解我们是如何运用函数式编程来操作序列的。其实我们可以把这种操作序列的方式再升华一下。例如,你可以把一个按钮的点击事件看作是一个序列: // 假设用户在进入页面到离开页面期间,总共点击按钮 3 次 // 按钮点击序列 let taps: Array<Void> = [(), (), ()] // 每次点击后弹出提示框 taps.forEach {

  • 本文向大家介绍详解JAVA 函数式编程,包括了详解JAVA 函数式编程的使用技巧和注意事项,需要的朋友参考一下 1.函数式接口 1.1概念: java中有且只有一个抽象方法的接口。 1.2格式: 1.3@FunctionalInterface注解: 与 @Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface 。该注 解可用于