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. Java虚拟机性能管理神器 - VisualVM(2) 入门

    一下载VisualVM 最新版本下载 历史版本下载 二启动VisualVM 三VisualVM用户目录 四VisualVM窗口 1应用程序窗口 2详情窗口 五VisualVM插件   Java虚拟机性 ...

  2. miRTarBase 数据库简介

    miRTarBase 是一个手 收集的,经过实验验证过miRNA靶基因的数据库,对于每条miRNA靶基因的记录, 都会赋予1个唯一的 miRNA-target interactions (简称MTs) ...

  3. c++ A类包含B类指针,B类包含A类指针的情况

    #include<stdio.h> class Bclass; class Aclass { public: friend Bclass; void func() { pB->fun ...

  4. svn管理码云项目

    1.设置SVN管理项目 进入项目->管理 2.获取SVN地址 3.SVN添加项目.单击右键 -> 检出->版本库Url(这里填写svn地址)

  5. 装饰模式(Decorator Pattern)--------结构型模式

    装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为.装饰模式降低类系统的耦合度,可以动态地增加或删除对象的职责,并使得需要装饰的具体构件类和具体装饰类可以独立变化,以便增加新的具体构件 ...

  6. maven添加本地jar到本地库中

    maven添加本地jar到本地库中(用于远端地址下载不了的情况) 在dos命令行执行以下命令将会吧ojdbc14-10.2.0.4.0.jar添加到本地库中(ps:必须已经安装了,maven,并配置了 ...

  7. Android开发中常用的库总结(持续更新)

    这篇文章用来收集Android开发中常用的库,都是实际使用过的.持续更新... 1.消息提示的小红点 微信,微博消息提示的小红点. 开源库地址:https://github.com/stefanjau ...

  8. 在window的cmd窗口下运行linux命令

    之前看很多视频老师都是用Linux命令操作命令框,感觉很方便,自己在cmd窗口试了一下,所有这些命令都提示不是内部或外部命令,后来发现了windows还有一个powershell命令行工具,用起来似乎 ...

  9. 系统安装SQL Sever2000后1433端口未开放,如何打开1433端口的解决方法

    这篇文章主要针对Win2003系统安装SQL Sever2000后1433端口未开放,如何打开1433端口的解决方法. 用了几年的Windows2003和SQL Server2000了,不过这个问题倒 ...

  10. js中的string.format

    String.prototype.format = function(args) { var result = this; if (arguments.length > 0) { if (arg ...