【C#进阶】拥抱Lambda(二)
语言的设计,真的是挺有意思的。第一次看这个代码[1]时,旁人随口了一句“哇,好多实心句号”。
当时马上一个想法是——怎么实现的?返回了对象,然后再调用方法?然后就放下了,后来发现,这个是真值得说一说的。
var sim = new InputSimulator();
sim.Keyboard
.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R)
.Sleep()
.TextEntry("notepad")
.Sleep()
.KeyPress(VirtualKeyCode.RETURN)
.Sleep()
.TextEntry("These are your orders if you choose to accept them...")
.TextEntry("This message will self destruct in 5 seconds.")
.Sleep()
.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()返回的IEnumerable类型,这是另一个故事。
这篇写得短一些,主要觉得讲的内容还是保持内容一致性的好,关于LINQ的学习,下一篇继续吧。
注释:
[1] 自 https://archive.codeplex.com/?p=inputsimulator
[2] 自《深入理解C#》(第3版)Jon Skeet 著 姚琪琳 译
【C#进阶】拥抱Lambda(二)的更多相关文章
- 【C#进阶】拥抱Lambda(一)
写在开头,好奇从这里开始(当时让加查询条件,结果竟然是一句话来发挥神奇作用): this.TestGrade = CriteriaHelper.NewObject<ITestCase, DtoT ...
- 当我们说线程安全时,到底在说什么——Java进阶系列(二)
原创文章,同步发自作者个人博客,转载请以超链接形式在文章开头处注明出处http://www.jasongj.com/java/thread_safe/ 多线程编程中的三个核心概念 原子性 这一点,跟数 ...
- [.net 面向对象程序设计进阶] (3) 正则表达式 (二) 高级应用
[.net 面向对象程序设计进阶] (2) 正则表达式 (二) 高级应用 上一节我们说到了C#使用正则表达式的几种方法(Replace,Match,Matches,IsMatch,Split等),还 ...
- 网站开发进阶(四十二)巧用clear:both
网站开发进阶(四十二)巧用clear:both 前言 我们在制作网页中用div+css或者称xhtml+css都会遇到一些很诡异的情况,明明布局正确,但是整个画面却混乱起来了,有时候在IE6下看的很正 ...
- Java进阶(三十二) HttpClient使用详解
Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...
- Java进阶(五十二)利用LOG4J生成服务日志
Java进阶(五十二)利用LOG4J生成服务日志 前言 由于论文写作需求,需要进行流程挖掘.前提是需要有真实的事件日志数据.真实的事件日志数据可以用来发现.监控和提升业务流程. 为了获得真实的事件日志 ...
- zuul进阶学习(二)
1. zuul进阶学习(二) 1.1. zuul对接apollo 1.1.1. Netflix Archaius 1.1.2. 定期拉 1.2. zuul生产管理实践 1.2.1. zuul网关参考部 ...
- Lambda(二)lambda表达式使用
Lambda(二)lambda表达式使用 Lambda 表达式组成: /* param list arrow lambda body (o1,o2) -> o1.getColor().Compa ...
- c#进阶之lambda表达式
阅读之前,先确保对委托有基本的了解,传送门 c#进阶之浅析委托和事件. lambda表达式雏形第一步 在委托那篇文章,绑定的的方法都是具名函数,为了简化书写,可以换成匿名函数 public deleg ...
随机推荐
- IDEA 文件列表隐藏某后缀文件
preferences -> Editor -> File Types -> ignore files and folders 添加后缀类型如: *.meta
- (转)用webbrowser做的网站登陆程序,如何获取cookie并且保存在程序中 (IE8有效) ,用途嘛,你懂的。
今天帮朋友做了个工具,用webbrowser做的,用户使用用户名密码登陆网站后,需要在后台下载和分析一些页面. 分析页面使用的是htmlparser .net版 里面唯一需要解决的问题是,登陆后的co ...
- 用python实现数学多元数学方程式计算
题目:公鸡5元钱一只,母鸡3元钱一只,小鸡3只一块钱,其中公鸡,母鸡,小鸡都必须有,问公鸡,母鸡,小鸡各买多少只刚好凑足100元钱? 一:数学算术分析: x+y+z=100 5x+3y+z/3=100 ...
- com/mysql/jdbc/Driver : Unsupported major.minor version 52.0
解决方案: 1.jdk7+老版5.0驱动com/mysql/jdbc/Driver 2.jdk8+新版6.0驱动com/mysql/cj/jdbc/Driver
- Linux 目录说解
目录 1.树状目录结构图 2./目录 3./etc/目录 4./usr/目录 5./var/目录 6./proc/目录 7./dev/目录 该文章主要来自于网络进行整理. 目录结构参考地址: http ...
- Java基础语法学习知识
基础概念 标识符1.由字母,数字,下划线,美元符组成2.首字母不能是数字3.不能是关键字和保留字4.能反映其作用 关键字1.有特定含义2.用于特定地方3.用来命名标识符 常量1.程序执行时值不变的量2 ...
- PKG_CONFIG_PATH变量 与 ld.so.conf 文件
一.编译和连接 一般来说,如果库的头文件不在 /usr/include 目录中,那么在编译的时候需要用 -I 参数指定其路径.由于同一个库在不同系统上可能位于不同的目录下,用户安装库的时候也可以将库安 ...
- understand试用笔记一阅读VS2010项目
一.查看vs2010项目 打开understand,File—New—Project...—Next—Next [向导第三步,选“Import Visual Sudio project files”] ...
- pat树之专题(30分)
(好好复习是王道) 1115. Counting Nodes in a BST (30) 分析:简单题——将bst树构造出来,然后给每个节点打上高度.最后求出树的高度.然后count树高的节点数加上树 ...
- BZOJ 4129 Haruna’s Breakfast (分块 + 带修莫队)
4129: Haruna’s Breakfast Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 835 Solved: 409[Submit][St ...