当前位置:
首页 > Python基础教程 >
-
C#教程之【C#进阶】拥抱Lambda(二)
语言的设计,真的是挺有意思的。第一次看这个代码[1]时,旁人随口了一句“哇,好多实心句号”。
当时马上一个想法是——怎么实现的?返回了对象,然后再调用方法?然后就放下了,后来发现,这个是真值得说一说的。
1. 神奇的链接(chaining)
1.1 拓展方法
想了很久该怎么引入话题,或者这样说,像这种写法,
if (str == null || str == “”)
相信刚刚开始编程的时候都这样写过,而C#语言规则里面,告诉我们可以这样写:
string.IsNullOrEmpty(str);
后来,有一天,我很自然地就写成这样了str.IsNullOrEmpty,当然,IDE都没有弹出IsNullOrEmpty这个函数我就知道不对了。
嗯,如果非要写成str.IsNullOrEmpty这样,大概会很麻烦。
首先string类型就是seal,重写一个string类那就……
可以写静态方法,但其实也不美观,因为还是要这样 IsNullOrEmpty_test(str), 那和string.IsNullOrEmpty(str); 是没有区别的。
这个时候,故事终于来到——拓展方法(Extension Methods)。
下个定义吧,好说话。
拓展方法,就是把对象自己作为第一个传入参数的静态方法。(这个“对象自己”,需要在形参前加个 this 前缀)
没有规则总是会乱套的,拓展方法有些语法[2]:
那么string.IsNullOrEmpty(str);能怎么改?
这样看来,可能会有一些疑问,编译器怎么决定要使用的拓展方法?怎么个“非请勿来”?
首先,如果总是会检测一下是不是实例方法;
如果不是,就会去查一个合适的拓展方法。它会检查当前的、引用的所有拓展方法。
顺带一提,前面提及的InputSimulator类确实这样实现的,思想上是一致的。
1.2 Lambda筛选与链接
LINQ里面.where().Select().OrderBy().等等的“点点点”,就是基于拓展方法的思路。
在Where()点击F12,见:
publicstatic IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
另外有一点值得提,Where()返回的是重新new的集合,占据内存空间的。
这篇写得短一些,主要觉得讲的内容还是保持内容一致性的好,关于LINQ的学习,下一篇继续吧。
当时马上一个想法是——怎么实现的?返回了对象,然后再调用方法?然后就放下了,后来发现,这个是真值得说一说的。
var sim = new InputSimulator(); sim.Keyboard .ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R) .Sleep(1000) .TextEntry("notepad") .Sleep(1000) .KeyPress(VirtualKeyCode.RETURN) .Sleep(1000) .TextEntry("These are your orders if you choose to accept them...") .TextEntry("This message will self destruct in 5 seconds.") .Sleep(5000) .ModifiedKeyStroke(VirtualKeyCode.MENU, VirtualKeyCode.SPACE) .KeyPress(VirtualKeyCode.DOWN) .KeyPress(VirtualKeyCode.RETURN);
1. 神奇的链接(chaining)
1.1 拓展方法
想了很久该怎么引入话题,或者这样说,像这种写法,
if (str == null || str == “”)
相信刚刚开始编程的时候都这样写过,而C#语言规则里面,告诉我们可以这样写:
string.IsNullOrEmpty(str);
后来,有一天,我很自然地就写成这样了str.IsNullOrEmpty,当然,IDE都没有弹出IsNullOrEmpty这个函数我就知道不对了。
嗯,如果非要写成str.IsNullOrEmpty这样,大概会很麻烦。
首先string类型就是seal,重写一个string类那就……
可以写静态方法,但其实也不美观,因为还是要这样 IsNullOrEmpty_test(str), 那和string.IsNullOrEmpty(str); 是没有区别的。
这个时候,故事终于来到——拓展方法(Extension Methods)。
下个定义吧,好说话。
拓展方法,就是把对象自己作为第一个传入参数的静态方法。(这个“对象自己”,需要在形参前加个 this 前缀)
没有规则总是会乱套的,拓展方法有些语法[2]:
l 必须在一个非嵌套的、非泛型的静态类中; l 至少有一个参数(就是对象它自己); l 第一个参数必须附加this关键字前缀; l 第一个参数不能有其他任何修饰符(比如out或ref); l 第一个参数的类型不能是指针类型。 |
那么string.IsNullOrEmpty(str);能怎么改?
class Program { static void Main(string[] args) { string str = ""; Console.WriteLine(str.IsNullOrEmpty()); } } static class NullUtil { public static bool IsNullOrEmpty(this string text) { return string.IsNullOrEmpty(text); } }
这样看来,可能会有一些疑问,编译器怎么决定要使用的拓展方法?怎么个“非请勿来”?
首先,如果总是会检测一下是不是实例方法;
如果不是,就会去查一个合适的拓展方法。它会检查当前的、引用的所有拓展方法。
TIPS:为了决定是否使用一个拓展方法,编译器必须能区分拓展方法与某静态类中恰好具有合适签名的其他方法。为此,它会检查类和方法是否具有System.Runtime.CompilerServices.ExtensionAttribute这个特性(它是.NET3.5新增的)。 |
顺带一提,前面提及的InputSimulator类确实这样实现的,思想上是一致的。
public class KeyboardSimulator : IKeyboardSimulator { ... public IKeyboardSimulator KeyPress(VirtualKeyCode keyCode) { var inputList = new InputBuilder().AddKeyPress(keyCode).ToArray(); SendSimulatedInput(inputList); return this; } ... }
1.2 Lambda筛选与链接
LINQ里面.where().Select().OrderBy().等等的“点点点”,就是基于拓展方法的思路。
var list = new List<string> { "a", "b", "c", "d", "a", "b", "c", "d", "a", "a" }; list = list.Where(a => a.Equals("a")).Reverse().ToList(); list.ForEach(a => Console.WriteLine(a));
在Where()点击F12,见:
publicstatic IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull(nameof (source)); if (predicate == null) throw Error.ArgumentNull(nameof (predicate)); if (source is Enumerable.Iterator<TSource>) return ((Enumerable.Iterator<TSource>) source).Where(predicate); if (source is TSource[]) return (IEnumerable<TSource>) new Enumerable.WhereArrayIterator<TSource>((TSource[]) source, predicate); if (source is List<TSource>) return (IEnumerable<TSource>) new Enumerable.WhereListIterator<TSource>((List<TSource>) source, predicate); return (IEnumerable<TSource>) new Enumerable.WhereEnumerableIterator<TSource>(source, predicate); }
另外有一点值得提,Where()返回的是重新new的集合,占据内存空间的。
这篇写得短一些,主要觉得讲的内容还是保持内容一致性的好,关于LINQ的学习,下一篇继续吧。
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式