C# 为支持LINQ添加了许多语言特性:

  • 隐式类型局部变量
  • 对象初始化器
  • Lambda表达式
  • 扩展方法
  • 匿名类型

了解这些新特性是全面了解LINQ的重要先解条件,因此请不要忽视它们.

(一)  隐式类型局部变量

processData这个类中的亮点是 {get;set;} 它是一个新特性, 系统会自动产生一个匿名私有变量.

 public Int32 Id { get; set; }
public Int64 Memory { get; set; }
public string Name { get; set; } public processData()
{ } public processData(Int32 id, Int64 mem, string name)
{
Id = id;
Memory = mem;
Name = name;
}

var让你无需要写两次变量的类型, 编译器会自动推导,可以有效的减少代码书写量.

ObjectDumper.write() 是一个自定义的类, 在本系列的源代码中会有提供, 它可以方便显示对象的内容.

   var process = new List<processData>();
foreach (var m in Process.GetProcesses())
{
var data = new processData();
data.Id = m.Id;
data.Name = m.ProcessName;
data.Memory = m.WorkingSet64;
process.Add(data);
}
ObjectDumper.Write(process);

运行结果:

(二)  对象初始化器

上面的代码可以利用processData类的构造函数进行优化.

 //用构造函数优化上面的代码
var process = new List<processData>();
foreach (var m in Process.GetProcesses())
{
process.Add(new processData(m.Id, m.WorkingSet64, m.ProcessName));
}
ObjectDumper.Write(process);

最佳做法是使用对象初始化器优化, 如下:

  //用对象初始化器优化上面的代码
var process = new List<processData>();
foreach (var m in Process.GetProcesses())
{
process.Add(new processData()
{
Id = m.Id,
Memory = m.WorkingSet64,
Name = m.ProcessName
});
}
ObjectDumper.Write(process);

在你敲上面代码时, 在{}中敲一下空格,  对象初始化器还可以支持智能感知. 相当方便.

从上面代码可以看出,有了对象初始化器, 好处很多:

  • 只需要一条语句完成对象初始化工作
  • 无需为简单对象提供构造函数
  • 无需要为实始化不同的属性而为类提供多个构造函数

(三)  Lambda表达式

要解释Lambda表达式首先要解释下面几个知识:

  • 委托
  • 匿名方法

1. 委托

C#的委托用处很大, 比如更新UI界面, 或者发挥类似函数指针的作用.

下面的例子中委托的作用类似于函数指针.

         delegate bool match<T>(T obj);
private void disProcess(match<Process> fun)
{
var process = new List<processData>();
foreach (var m in Process.GetProcesses())
{
if (fun(m))
{
process.Add(new processData()
{
Id = m.Id,
Memory = m.WorkingSet64,
Name = m.ProcessName
});
}
}
ObjectDumper.Write(process);
}
bool filter(Process obj)
{
return obj.WorkingSet64 > * * ;
}
private void button7_Click(object sender, EventArgs e)
{
disProcess(filter);
}

结果是筛选出大于10M的进程信息.

2. 匿名方法

匿名方法不用显式定义方法名, 降低了代码量.

下面的代码, 相比之前的代码来说, 就是省略了filter函数的名字, 只用了它的函数体代码.

代码改进部分如下:

   //演示匿名方法
disProcess(delegate(Process pro)
{
return pro.WorkingSet64 > * * ;
}
);

C#在List<T>和Array类型中添加了一些方法, 如ForEach,Find以方便使用匿名方法

下面我们修改下disProcess() 函数, 演示一下对process使用Find方法查找进程devenv.

  private void disProcess(match<Process> fun)
{
var process = new List<processData>();
foreach (var m in Process.GetProcesses())
{ if (fun(m))
{
process.Add(new processData()
{
Id = m.Id,
Memory = m.WorkingSet64,
Name = m.ProcessName
});
}
} //C#在List<T>和Array类型中添加了一些方法, 如ForEach,Find以方便使用匿名方法
var list1= process.Find(delegate(processData obj)
{
return obj.Name == "devenv";
});

ObjectDumper.Write(process);
}

下面我们可以直接使用Lambda表达式, 代替匿名方法.

 //演示Lambda表达式
//读作, 对传入的Process对象,如果内存占用超过10M,则返回true
disProcess(s => s.WorkingSet64 > * * );

Lambda表达式的好处是, 无需要提供参数类型, 由编译器从方法的签名中自动取得.

除了实现匿名方法的功能外, Lambda还提供额外的好处:

  • 无需要提供参数类型
  • 支持用语句块或者表达式作为方法体, 匿名方法只能使用语句块
  • 支持通过参数选择重载函数
  • 带有表达式体的Lambda表达式能够转化为表达式树

 (四) 扩展方法

下面的例子要做一件事:查找内在占用大于10M的进程,计算总内存占用,转为MB方式表示

相对于使用普通方法,如果使用扩展方法来实现,它的语法结构易于使程序员把许多操作用.串联起来.

这样代码的实际执行顺序和阅读顺序就完全致.完全符合人的思维.

另一方面,扩展方法被智能感知支持,你要类型后.一下,就可以快速找到扩展方法.

   private void button10_Click(object sender, EventArgs e)
{
//我们编写三个扩展方法,按顺序执行得到结果
//1. FilterOutSomeProcess() 过滤出一部分符合条件的Process
//2. TotalMemory() 统计这些Process的内存总占用
//3. BytesToMegaBytes() 把上述内存占用转为MB方式表示 //查找内在占用大于10M的进程,计算总内存占用,转为MB方式表示.
Console.WriteLine("查找内在占用大于10M的进程,计算总内存占用,转为MB方式表示:"
+ Environment.NewLine);
Console.WriteLine(
Process.GetProcesses()
.FilterOutSomeProcess(filter2)
.TotalMemory()
.BytesToMegaBytes()+"MB"

);
} bool filter2(long mem)
{
if (mem > * * ) return true;
return false;
}

下面是上面三个扩展方法的定义部分.

可以看见,扩展方法在要扩展类的类型前面加上关键字this, 其它的与普通方法没什么不同.

在智能感知时,扩展方法图标有个向下的小箭头,以和普通方法区别开来.

  delegate bool filterDelegate(long mem);
static class externFun
{
public static List<processData> FilterOutSomeProcess(this Process[] pro,filterDelegate fun)
{
var proList = new List<processData>();
foreach (var m in pro)
{
if(fun(m.WorkingSet64))
proList.Add(new processData()
{
Id = m.Id,
Memory = m.WorkingSet64,
Name = m.ProcessName
});
}
return proList;
} public static long TotalMemory(this List<processData> data)
{
long sum=;
data.ForEach(s => sum += s.Memory);
return sum;
} public static float BytesToMegaBytes(this long sum)
{
return (float)sum / 1024f / 1024f;
} }

结果如下:

LINQ也带来一系列扩展方法,它们也可以不用于LINQ中.使用它们要包含 using System.Linq

下面我们介绍几个:

OrderByDescending

Take

Sum

我们通过一个例子介绍上面三个扩展方法.

这个例子是想实现: 进程按内存占用排序,取前两名耗内存大户并计算它们耗费的总内存,用MB表示

  private void button11_Click(object sender, EventArgs e)
{
var list1 = new List<processData>();
foreach (var m in Process.GetProcesses())
{
list1.Add(new processData()
{
Id = m.Id,
Memory = m.WorkingSet64,
Name = m.ProcessName
});
}
Console.WriteLine("进程按内存占用排序,取前两名耗内存大户并计算它们耗费的总内存,用MB表示"+
Environment.NewLine);
Console.WriteLine(
list1
.OrderByDescending(s => s.Memory)
.Take()
.Sum(s => s.Memory) / 1024f / 1024f +"MB"

);
}

关于扩展方法的几点说明:

1. 扩展方法必须定义于静态类,自身应该为public,static

2. 如果实例方法和扩展方法同名,先执行实例方法,扩展方法执行优先级要低.

3. 扩展方法无法访问类型的非公有成员.

(五) 匿名类型

有了匿名类型,我们可以不再使用上面定义的processData类.而完成了同样的事情.

  private void button12_Click(object sender, EventArgs e)
{
var list1 = new List<object>();
foreach (var m in Process.GetProcesses())
{
//匿名类型可以不指定属性的名称, 指定属性的名称仅仅是为了让代码好懂些
list1.Add(
new
{
//Id = m.Id,
//Memory = m.WorkingSet64,
//Name = m.ProcessName
m.Id,
m.WorkingSet64,
m.ProcessName
});
}
ObjectDumper.Write(list1); var obj = ReturnAGeneric(() => new
{
Time = DateTime.Now,
Name = "hackpig"
});
//下面的代码是非法的, 这是因为匿名类型的实例是不可变的,它没有set
//obj.Name = "lxy1";
//obj.Time = DateTime.Now;
ObjectDumper.Write(obj);

} public static TResult ReturnAGeneric<TResult>(Func<TResult> creator)
{
return creator();
}

匿名类型的好处是无须特地编写专门的类型来存放这些临时性数据,可以大大加快程序的编写速度.

匿名类型有一些限制,如下:

  • 在定义匿名类型的方法外想操作匿名类型,只有依靠反射.
  • 匿名类型只适合存放临时的数据,不能做为方法返回类型.(泛型返回值的方法中除外)
  • 匿名类型一旦创建了实例,那么这个实例的值就固定不可变的,也就是不允许再set了.之所以这样限制,就是要为函数式编程基于值的编程风格服务,避免不必要的副作用.另外在PLINQ中,这个特性至关重要,永远不会改变的对象大大降低了程序设计中对并发处理的难度.

这本书前两章的内容到此就结束了,笔者感觉讲解得还是蛮精彩的.

下面放上练习的源代码,这些代码,有些已经不同于源书代码,是在理解的基础上改编的.

本文源代码

原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/

LinQ实战学习笔记(二) C#增强特性的更多相关文章

  1. LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树

    序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...

  2. LinQ实战学习笔记(一) LINQ to (Objects, XML, SQL) 入门初步

    LINQ对于笔者来说, 优美而浓缩的代码让人震惊. 研究LINQ就是在艺术化自己的代码. 之前只是走马观花学会了基本的语法, 但是经常在CSDN看到令人惊讶自叹不如的LINQ代码, 还是让人羡慕嫉妒恨 ...

  3. LinQ实战学习笔记(四) LINQ to Object, 常用查询操作符

    这一篇介绍了下面的内容: 查询object数组 查询强类型数组 查询泛型字典 查询字符串 SelectMany 索引 Distinct操作符 排序 嵌套查询 分组 组连接 内连接 左外连接 交叉连接 ...

  4. 基于.net的分布式系统限流组件 C# DataGridView绑定List对象时,利用BindingList来实现增删查改 .net中ThreadPool与Task的认识总结 C# 排序技术研究与对比 基于.net的通用内存缓存模型组件 Scala学习笔记:重要语法特性

    基于.net的分布式系统限流组件   在互联网应用中,流量洪峰是常有的事情.在应对流量洪峰时,通用的处理模式一般有排队.限流,这样可以非常直接有效的保护系统,防止系统被打爆.另外,通过限流技术手段,可 ...

  5. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  6. Django学习笔记二

    Django学习笔记二 模型类,字段,选项,查询,关联,聚合函数,管理器, 一 字段属性和选项 1.1 模型类属性命名限制 1)不能是python的保留关键字. 2)不允许使用连续的下划线,这是由dj ...

  7. ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring

    接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...

  8. amazeui学习笔记二(进阶开发1)--项目结构structure

    amazeui学习笔记二(进阶开发1)--项目结构structure 一.总结 1.项目结构:是说的amazeui在github上面的项目结构,二次开发amazeui用 二.项目结构structure ...

  9. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

随机推荐

  1. linux stat命令参数及用法详解

    功能说明:显示inode内容.语 法:stat [文件或目录]补充说明:stat以文字的格式来显示inode的内容. ls 命令及其许多参数提供了一些非常有用的文件信息.另一个不太为人所熟知的命令 s ...

  2. python 程序构架浅析

    定义:通常的 Python 程序的构架是指:将一个程序分割为源代码文件的集合以及将这些部分连接在一起的方法. python的程序构架可表示为: 一个python程序就是一个模块的系统.它有一个顶层文件 ...

  3. Ubuntu下使用dialog制作菜单执行简单脚本

    新建test5 #!/bin/bash #using select in the menu temp=$(mktemp -t test.XXXXXX) temp2=$(mktemp -t test2. ...

  4. mysql触发器应用和创建表错误代码: 1118 Row size too large. 解决

    1.针对数据库查询问题的方便,可以建立重要表的log备份记录表,在主表的添加,修改,删除添加触发器,修改触发器增加触发字段的点,限制条件. 数据库log表查问题比从线上多台服务器上下载日志文件相对方便 ...

  5. 【转】ZooKeeper详细介绍和使用第一节

    一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技术.那么什么是分布式协调技术?那么我来告诉大家,其实分布式协调技术 主要用来解决分布式环境当中多个进程之间的 ...

  6. A标签添加JS事件,不跳转不刷新办法

    <a href="javascript:;" id="submit-btn" class="submit-btn" title=&qu ...

  7. nginx: [emerg] getpwnam(“www”) failed错误

    linux 64系统中安装nginx时如果出现错误:nginx: [emerg] getpwnam(“www”) failed in ........解决方法1:      在nginx.conf中 ...

  8. DotNetBar如何控制窗体样式

    在C#中使用控件DevComponents.DotNetBar时,如何创建一个漂亮的窗口,并控制窗体样式呢?   1.新建一个DotNetBar窗体             2.使OFFICE窗口风格 ...

  9. jdbc数据访问技术

    jdbc数据访问技术 1.JDBC如何做事务处理? Con.setAutoCommit(false) Con.commit(); Con.rollback(); 2.写出几个在Jdbc中常用的接口 p ...

  10. 九度 1464:Hello World for U

    题目描述: Given any string of N (>=5) characters, you are asked to form the characters into the shape ...