【C#/.NET】控制台上动态构建中间件管道

5e89e6468e36e463407379e08ec5cd85.png

如上图所示:我们将会在下面文章上一步一步变形实现出这样的功能。


一、傻瓜式执行演示

首先建立控制台项目,创建Begin() FirstMiddleware() SecondMiddleware() End() 三个函数

1        /// <summary>2        /// 开始执行前3        /// </summary>4        public static void Begin()5        {6            Console.WriteLine("begin executing");7        }89        /// <summary>
10        /// 执行结束
11        /// </summary>
12        public static void End()
13        {
14            Console.WriteLine("end executed");
15        }
16
17        public static void FirstMiddleware()
18        {
19            Console.WriteLine("第一个中间件");
20        }
21        public static void SecondMiddleware()
22        {
23            Console.WriteLine("第二个中间件");
24        }

按照如下顺序执行,并显示结果

1        static void Main(string[] args)2        {3            //Console.WriteLine("Hello World!");4            #region 傻瓜式演示中间件执行方法5            Begin();6            FirstMiddleware();7            End();8            Console.WriteLine("-------------------");9            Begin();
10            SecondMiddleware();
11            End();
12            #endregion
13        }

4b09e0bc473fc3719c97c84f6e9aadba.png

二、封装傻瓜式执行函数

这个Begin() End() 两个方法会执行多次,所以我们可以选择封装一下

1        /// <summary>2        /// 封装一个执行方法 减少重复代码3        /// 入参可以传递一个无参数 无返回值函数 用内置委托接受4        /// </summary>5        /// <param name="function"></param>6        public static void CommonExecute(Action function)7        {8            Begin();9            function();
10            End();
11        }

如下调用,执行结果和前文一样

1            #region 封装傻瓜式执行函数
2            CommonExecute(FirstMiddleware);
3            Console.WriteLine("-------------------");
4            CommonExecute(SecondMiddleware);
5            #endregion

三、利用lambda变形简化

这里我们需要做个演变,就是将我们要执行的CommonExecute()函数用lambda表达式包裹为另一个函数的参数传递;
于是创建一个ExtraExecute() 函数

1        public static void ExtraExecute(Action function)2        {3            try4            {5                Console.WriteLine("try here");6                function();7            }8            catch (Exception)9            {
10
11                throw;
12            }
13        }

我们将包裹后的CommonExecute()作为入参传递给ExtraExecute()调用,如下所示:

1            ExtraExecute(() => CommonExecute(FirstMiddleware)); // 执行第一个中间件,先执行ExtraExecute() 再执行CommonExecute()
2            Console.WriteLine("-----------");
3            ExtraExecute(() => CommonExecute(SecondMiddleware)); // 执行第二个中间件

ea96f8a2aa98246d49526893a314c061.png

通过观察发现CommonExecute()ExtraExecute()方法签名一样,所以我们可以调换下两者的执行顺序,如下所示:

1            Console.WriteLine("-----------");
2            // 更改中间件调用顺序 先执行CommonExecute() 再执行ExtraExecute()
3            CommonExecute(() => ExtraExecute(FirstMiddleware));

2b77d13679cbd028e4754a738e974b60.png

带参创建中间件调用链

我们刚刚演示了无参的中间件调用,现在给中间件执行体增加入参,新增FirstPipe(string msg, Actionfunc) SecondPipe(string msg, Actionfunc) ThirdPipe(string msg, Actionfunc) 三个函数,如下调用,核心原则就是将中间件执行函数包裹成参数传递给下一个执行的函数

1 Action<string> pipe = (msg) => ThirdPipe(msg,
2                                                        (msg1) => SecondPipe(msg1,
3                                                            (msg2) => FirstPipe(msg2, FirstMiddleware)));
4 pipe("Hello World"); // 调用

50103dc73dfa7d165033f330ffa50176.png

动态创建中间件管道模型

从带参创建中间件调用链上我们发现,我们无法把这个管道变成动态的,那么如何才能将中间件动态传入以及动态改变调用顺序呢?
通过分析我发现,一个管道执行的最基本单元可以像下面这样定义

1        public abstract class DynamicPipeBase2        {3            protected readonly Action<string> _action;45            public DynamicPipeBase(Action<string> action)6            {7                this._action = action;8            }9            public abstract void Handle(string msg); // 调用执行中间件函数体
10        }

然后定义三个函数继承 DynamicPipeBase()

1        /// <summary>2        /// 第三个中间件3        /// </summary>4        public class ThirdSelfPipe : DynamicPipeBase5        {6            public ThirdSelfPipe(Action<string> action):base(action)7            {89            }
10            public override void Handle(string msg)
11            {
12                Console.WriteLine("Third Pipe Begin executing");
13                _action(msg);
14                Console.WriteLine("Third Pipe End executed");
15            }
16        }
17
18        public class SecondSelfPipe : DynamicPipeBase
19        {
20            public SecondSelfPipe(Action<string> action) : base(action)
21            {
22
23            }
24            public override void Handle(string msg)
25            {
26                Console.WriteLine("Second Pipe Begin executing");
27                _action(msg);
28                Console.WriteLine("Second Pipe End executed");
29            }
30        }
31
32        /// <summary>
33        /// 第一个中间件
34        /// </summary>
35        public class FirstSelfPipe : DynamicPipeBase
36        {
37            public FirstSelfPipe(Action<string> action) : base(action)
38            {
39
40            }
41            public override void Handle(string msg)
42            {
43                Console.WriteLine("First Pipe Begin executing");
44                _action(msg);
45                Console.WriteLine("First Pipe End executed");
46            }
47        }

有了中间件,我们接着只需要构建管道即可,如下所示

1        /// <summary>2        /// 存储中间件: List<Type> _types;3        /// 生成中间件调用链: GeneratePipe4        /// 构建回调:Build5        /// </summary>6        public class PipeBuilder7        {8            protected readonly Action<string> _mainAction;9            List<Type> _types;
10            public PipeBuilder(Action<string> mainAction)
11            {
12                _mainAction = mainAction;
13                _types = new List<Type>();
14            }
15            public PipeBuilder AddPipe(Type type)
16            {
17                _types.Add(type);
18                return this;
19            }
20
21            private Action<string> GeneratePipe(int index)
22            {
23                if(index==_types.Count-1)
24                {
25                    var finalType= (DynamicPipeBase)Activator.CreateInstance(_types[index], _mainAction);
26                    return finalType.Handle;
27                }
28                else
29                {
30                    var childHalde= GeneratePipe(index + 1);
31                    return ((DynamicPipeBase)Activator.CreateInstance(_types[index], childHalde)).Handle;
32                } 
33
34            }
35
36            public Action<string> Build()
37            {
38                return GeneratePipe(0);
39            }
40        }

最终我们在上端调用:

1            #region 动态创建中间件管道模型
2            Action<string> pipeChain = new PipeBuilder(MainAction)
3                .AddPipe(typeof(ThirdSelfPipe)) // 随意添加多个中间件执行单元
4                .AddPipe(typeof(SecondSelfPipe))
5                .AddPipe(typeof(FirstSelfPipe))
6                .Build();
7            pipeChain("Hello World");
8            Console.WriteLine("-------------");
9            #endregion

这样便实现了文章开头展示的效果。

【社区不定期分享.NET知识】,记得点赞关注哦!

如需源码,关注后台后添加小编微信即可~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290760.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SON Web Token设计单点登录系统

2019独角兽企业重金招聘Python工程师标准>>> 上次在《JSON Web Token - 在Web应用间安全地传递信息》中我提到了JSON Web Token可以用来设计单点登录系统。我尝试用八幅漫画先让大家理解如何设计正常的用户认证系统&#xff0c;然后再延伸到单点登录系统。 如果还没…

Avalonia跨平台入门第十篇之控件的锁定

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底;今天趁着有时间接着对拖放到Canvas上的控件进行锁定的效果,最终实现的效果如下图:关于控件的锁定实现代码:接下来的文章中我会分享控件在Canvas范围内拖拽和…

ios之第一个图形化界面

1、创建ios项目 1、create Xcode ->simpleViewApplication -> input Program name 2、在控制器里面加入代码 我们在viewControl.m里面加上UILabel控件&#xff0c;这个控件和Android 里面的TextView类似&#xff0c;具体代码如下// // ViewController.m // SecondHello…

Memcached简介

在Web服务开发中&#xff0c;服务端缓存是服务实现中所常常采用的一种提高服务性能的方法。其通过记录某部分计算结果来尝试避免再次执行得到该结果所需要的复杂计算&#xff0c;从而提高了服务的运行效率。 除了能够提高服务的运行效率之外&#xff0c;服务端缓存还常常用来提…

JAVA设计模式之门面模式(外观模式)

医院的例子 现代的软件系统都是比较复杂的&#xff0c;设计师处理复杂系统的一个常见方法便是将其“分而治之”&#xff0c;把一个系统划分为几个较小的子系统。如果把医院作为一个子系统&#xff0c;按照部门职能&#xff0c;这个系统可以划分为挂号、门诊、划价、化验、收费、…

里程碑 .Net7再更新,从此彻底碾压Java!

.NET 7 Preview1发布了&#xff0c;没时间实操&#xff1f;先快来看看.NET7的七项重大改进&#xff01;1、不再支持.NET 7应用程序、运行时和SDK的多级查找&#xff08;MLL&#xff09;2、PATH停止向.NET 7运行时和SDK添加32位.NET3、默认情况下&#xff0c; dotnet build/publ…

软件架构知识体系

2019独角兽企业重金招聘Python工程师标准>>> 由于[GOF95]是论述软件模式的著作的第一本&#xff0c;也是OO设计理论著作中最流行的一本&#xff0c;因此有些人常常使用设计模式&#xff08;Design Pattern&#xff09;一词来指所有直接处理软件的架构、设计、程序实…

C#不要再使用Npoi啦,使用MiniExcel操作Excel文件更快更高效!

1.简介MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。目前主流框架如Npoi 需要将数据全载入到内存方便操作&#xff0c;但这会导致内存消耗问题。MiniExcel 尝试以 Stream 角度写底层算法逻辑&#xff0c;能让原本1000多MB占用降低到几MB&#xff0c;避免内…

go和python切片的不同

2019独角兽企业重金招聘Python工程师标准>>> go有切片slice类型&#xff0c;python有列表和元组&#xff0c;这两种语言都有切片操作。 但是它们的切片操作是完全不同的。 首先说第一个&#xff0c;go的切片&#xff0c;其成员是相同类型的&#xff0c;python的列…

编程算法 - 切割排序 代码(C)

切割排序 代码(C)本文地址: http://blog.csdn.net/caroline_wendy排序切割, 把一个数组分为, 大于k\小于k\等于k的三个部分.能够使用高速排序的Partition函数, 进行处理, 把大于k的放在左边, 小于k的放在右边.使用一个变量记录中间的位置, 则时间复杂度为O(3n/2).代码:/** main…

【C#/.NET】.NET6中全局异常处理

微信公众号&#xff1a;趣编程ACE关注可了解每日一更的.NET日常实战开发技巧&#xff0c;欢迎公众号留言开发 获取源码;.NET6中全局异常处理异常处理是我们在程序开发中不可或缺的一环&#xff0c;下文我将会结合程序Sample讲解如何在.NET6中有效处理异常。Try-Ctach 块包裹自定…

JAVA学习笔记--初识容器类库

一、前言 JAVA中一切皆为对象&#xff0c;因而&#xff0c;持有对象显得尤为重要。 在JAVA中&#xff0c;我们可以通过创建一个对象的引用的方式来持有对象&#xff1a; HoldingObject holding; 也可以创建一个对象数组来持有一组特定类型的对象&#xff1a; HoldingObject hol…

如何保证执行异步方法时不会遗漏 await 关键字

前言在.NET Core 中已经广泛使用异步编程&#xff0c;代码中充斥着大量的 async 和 await 关键字。但有时候&#xff0c;调用一个异步方法时可能会忘了写 await。这会造成什么问题呢&#xff1f;问题重现示例代码如下&#xff1a;[HttpGet] public async Task<IEnumerable&l…

Avalonia跨平台入门第十二篇之动画效果

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底、控件的锁定、自定义Window样式;今天趁着空闲时间接着去摸索简单的动画效果,毕竟有点动画的东西还是挺有意思的;最终实现的效果如下图:使用了Margin实现左右…

python之解析最简单的xml

1、person.xm文件如下 2、用xml.etree.ElementTree解析person.xml的实现 3、效果如下 4、总结 python里面的list []相当于java里面的list&#xff0c;然后可以改变其中的值。

mysql忘记密码,怎么办?

mysql忘记密码&#xff0c;怎么办&#xff1f;我们经常需要修改mySQL的密码&#xff0c;比如时间久了忘记了MySQL的密码&#xff0c;也或者是使用了一台别人使用过的电脑&#xff0c;不知道之前密码的情况下&#xff0c;又想使用MySQL&#xff0c;怎么办呢&#xff1f;准备工作…

三分钟学会缓存工具DiskLruCache

DiskLruCache是一个十分好用的android缓存工具&#xff0c;我们可以从GitHub上下载其源码&#xff1a;https://github.com/JakeWharton/DiskLruCache DiskLruCache所有的数据都存储在/storage/emulated/0/Android/data/应用包名/cache/XXX文件夹中(你也可以修改&#xff0c;但不…

【数据挖掘】知识总结——背景、定义、一般流程及应用(一)

数据挖掘知识总结&#xff08;一&#xff09; 1.数据挖掘产生的背景&&驱动力 DRIP&#xff08;Data Rich Information Poor&#xff09; 四种主要技术激发了人们对数据挖掘技术的开发、应用和研究的兴趣&#xff1a; 超大规模数据库的出现&#xff0c;如商业数据仓…

LinkedIn联合创始人:硅谷也就700万人,为什么能创建这么多瞩目的公司 ?

很多人不解&#xff1a;现在创业公司这么多&#xff0c;在世界任何地方都有很多人懂技术&#xff0c;营销&#xff0c;也有VC&#xff0c;可以组建团队&#xff0c;那为啥非要在硅谷做呢&#xff1f;作者董飞&#xff0c;整理了 Linkedin 创始人 Reid Hoffman 在CS183C 课程的分…

Docker容器安全的8大风险和33个最佳实践丨IDCF

作者&#xff1a;StackRox译者&#xff1a;冬哥原文&#xff1a;https://www.stackrox.io/blog/docker-security-101/容器以及例如Kubernetes等编排器开启了应用程序开发方法的新时代&#xff0c;支持微服务架构以及持续开发和交付。根据我们最新的容器状态和 Kubernetes 安全报…