做互联网小程序 和网站有没有前景wordpress加slider
做互联网小程序 和网站有没有前景,wordpress加slider,上海网站制作上海网站制作,网站开发后台指什么一、匿名类#xff1a;[ C# 3.0/.NET 3.x 新增特性 ] 1.1 不好意思#xff0c;我匿了 在开发中#xff0c;我们有时会像下面的代码一样声明一个匿名类#xff1a;可以看出#xff0c;在匿名类的语法中并没有为其命名#xff0c;而是直接的一个new { }就完事了。从外部看来…一、匿名类[ C# 3.0/.NET 3.x 新增特性 ] 1.1 不好意思我匿了 在开发中我们有时会像下面的代码一样声明一个匿名类可以看出在匿名类的语法中并没有为其命名而是直接的一个new { }就完事了。从外部看来我们根本无法知道这个类是干神马的也不知道它有何作用。 var annoyCla1 new {ID 10010,Name EdisonChou,Age 25 };Console.WriteLine(ID:{0}-Name:{1}-Age:{2}, annoyCla1.ID,annoyCla1.Name, annoyCla1.Age); 经过调试运行我们发现匿名类完全可以实现具名类的效果 1.2 深入匿名类背后 既然我们发现匿名类可以完全实现具名类的效果那么我们可以大胆猜测编译器肯定在内部帮我们生成了一个类似具名类的class于是我们还是借助反编译工具对其进行探索。通过Reflector反编译我们找到了编译器生成的匿名类如下图所示 从上图可以看出 1匿名类被编译后会生成一个[泛型类]可以看到上图中的f__AnonymousType0IDj__TPar, Namej__TPar, Agej__TPar就是一个泛型类 2匿名类所生成的属性都是只读的可以看出与其对应的字段也是只读的 所以如果我们在程序中为属性赋值那么会出现错误 3可以看出匿名类还重写了基类的三个方法Equals,GetHashCode和ToString我们可以看看它为我们所生成的ToString方法是怎么来实现的 实现的效果如下图所示 1.3 匿名类的共享 可以想象一下如果我们的代码中定义了很多匿名类那么是不是编译器会为每一个匿名类都生成一个泛型类呢答案是否定的编译器考虑得很远避免了重复地生成类型。换句话说定义了多个匿名类的话如果符合一定条件则可以共享一个泛型类。下面我们就来看看有哪几种情况 1如果定义的匿名类与之前定义过的一模一样属性类型和顺序都一致那么默认共享前一个泛型类 var annoyCla1 new {ID 10010,Name EdisonChou,Age 25 };Console.WriteLine(ID:{0}-Name:{1}-Age:{2}, annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);Console.WriteLine(annoyCla1.ToString());// 02.属性类型和顺序与annoyCla1一致那么共同使用一个匿名类var annoyCla2 new {ID 10086,Name WncudChou,Age 25 };Console.WriteLine(ID:{0}-Name:{1}-Age:{2}, annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);Console.WriteLine(Is The Same Class of 1 and 2:{0},annoyCla1.GetType() annoyCla2.GetType()); 通过上述代码中的最后两行我们可以判断其是否是一个类型答案是True 2如果属性名称和顺序一致但属性类型不同那么还是共同使用一个泛型类只是泛型参数改变了而已所以在运行时会生成不同的类 var annoyCla3 new {ID EdisonChou,Name 10010,Age 25 };Console.WriteLine(ID:{0}-Name:{1}-Age:{2}, annoyCla3.ID,annoyCla3.Name, annoyCla3.Age);Console.WriteLine(Is The Same Class of 2 and 3:{0},annoyCla3.GetType() annoyCla2.GetType()); 我们刚刚说到虽然共享了同一个泛型类只是泛型参数改变了而已所以在运行时会生成不同的类。所以那么可以猜测到最后两行代码所显示的结果应该是False他们虽然都使用了一个泛型类但是在运行时生成了两个不同的类。 3如果数据型名称和类型相同但顺序不同那么编译器会重新创建一个匿名类 var annoyCla4 new {Name EdisonChou,ID 10010,Age 25 };Console.WriteLine(ID:{0}-Name:{1}-Age:{2}, annoyCla4.ID,annoyCla4.Name, annoyCla4.Age);Console.WriteLine(Is The Same Class of 2 and 4:{0},annoyCla4.GetType() annoyCla2.GetType()); 运行判断结果为False 通过Reflector可以发现编译器确实重新生成了一个泛型类 二、匿名方法[ C# 2.0/.NET 2.0 新增特性 ] 2.1 从委托的声明说起 C#中的匿名方法是在C#2.0引入的它终结了C#2.0之前版本声明委托的唯一方法是使用命名方法的时代。不过这里我们还是看一下在没有匿名方法之前我们是如何声明委托的。 1首先定义一个委托类型 publicdelegate void DelegateTest(string testName); 2编写一个符合委托规定的命名方法 publicvoid TestFunc(string name) {Console.WriteLine(Hello,{0}, name);} 3最后声明一个委托实例 DelegateTest dgTest new DelegateTest(TestFunc);dgTest(Edison Chou); 4调试运行可以得到以下输出 由上面的步凑可以看出我们要声明一个委托实例要为其编写一个符合规定的命名方法。但是如果程序中这个方法只被这个委托使用的话总会感觉代码结构有点浪费。于是微软引入了匿名方法使用匿名方法声明委托就会使代码结构变得简洁也会省去实例化的一些开销。 2.2 引入匿名方法 1首先我们来看看上面的例子如何使用匿名方法来实现 DelegateTest dgTest2 new DelegateTest(delegate(string name) {Console.WriteLine(Good,{0}, name);
}); 从运行结果图中可以看出原本需要传递方法名的地方我们直接传递了一个方法这个方法以delegate(参数){方法体}的格式编写在{}里边直接写了方法体内容。于是我们不禁欢呼雀跃又可以简化一些工作量咯 2其次我们将生成的程序通过Reflector反编译看看匿名方法是怎么帮我们实现命名方法的效果的。 ①我们可以看到在编译生成的类中除了我们自己定义的方法外还多了两个莫名其妙的成员 ②经过一一查看原来编译器帮我们生成了一个私有的委托对象以及一个私有的静态方法。我们可以大胆猜测原来匿名方法不是没有名字的方法还是生成了一个有名字的方法只不过这个方法的名字被藏匿起来了而且方法名是编译器生成的。 ③经过上面的分析我们还是不甚了解到底匿名方法委托对象在程序中是怎么体现的这里我们需要查看Main方法但是通过C#代码我们没有发现一点可以帮助我们理解的。这时我们想要刨根究底就有点麻烦了。还好在高人指点下我们知道可以借助IL中间代码来分析一下。于是在Reflector中切换展示语言将C#改为IL就会看到另外一番天地。 3由上面的分析我们可以做出结论编译器对于匿名方法帮我们做了两件事一是生成了一个私有静态的委托对象和一个私有静态方法二是将生成的方法的地址存入了委托在运行时调用委托对象的Invoke方法执行该委托对象所持有的方法。因此我们也可以看出匿名方法需要结合委托使用。 2.3 匿名方法扩展 1匿名方法语法糖—更加简化你的代码 在开发中我们往往会采用语法糖来写匿名方法例如下面所示 DelegateTest dgTest3 delegate(string name) {Console.WriteLine(Goodbye,{0}, name);};dgTest3(Edison Chou); 可以看出使用该语法糖将new DelegateTest()也去掉了。可见编译器让我们越来越轻松了。 2传参也有大学问—向方法中传入匿名方法作为参数 ①在开发中我们往往声明了一个方法其参数是一个委托对象可以接受任何符合委托定义的方法。 staticvoid InvokeMethod(DelegateTest dg) {dg(Edison Chou);} ②我们可以将已经定义的方法地址作为参数传入InvokeMethod方法例如InvokeMethod(TestFunc); 当然我们也可以使用匿名方法不需要单独定义就可以调用InvokeMethod方法。 InvokeMethod(delegate(string name) {Console.WriteLine(Fuck,{0}, name);}); 3省略省略再省略—省略大括号 经过编译器的不断优化我们发现连delegate后边的()都可以省略了我们可以看看下面一段代码 InvokeMethod(delegate { Console.WriteLine(I love C sharp!); }); 而我们之前的定义是这样的 publicdelegate void DelegateTest(string testName); staticvoid InvokeMethod(DelegateTest dg) {dg(Edison Chou);} 我们发现定义时方法是需要传递一个string类型的参数的但是我们省略了deletegate后面的括号之后就没有参数了那么结果又是什么呢经过调试发现结果输出的是I love C sharp! 这时我们就有点百思不得其解了明明都没有定义参数为何还是满足了符合委托定义的参数条件呢于是我们带着问题还是借助Reflector去一探究竟。 ①在Main函数中可以看到编译器为我们自动加上了符合DelegateTest这个委托定义的方法参数即一个string类型的字符串。虽然输出的是I love C sharp,但它确实是符合方法定义的因为它会接受一个string类型的参数尽管在方法体中没有使用到这个参数。 ②刚刚在Main函数中看到了匿名方法现在可以看看编译器为我们所生成的命名方法。 三、扩展方法[ C# 3.0/.NET 3.x 新增特性 ] 3.1 神奇—初玩扩展方法 1提到扩展方法我想大部分的园友都不陌生了。不过还是来看看MSDN的定义 MSDN 说扩展方法使您能够向现有类型添加方法而无需创建新的派生类型、重新编译或以其他方式修改原始类型。这里的添加之所以使用引号是因为并没有真正地向指定类型添加方法。 那么有时候我们会问为什么要有扩展方法呢这里我们可以顾名思义地想一下扩展扩展那么肯定是涉及到可扩展性。在抽象工厂模式中我们可以通过新增一个工厂类而不需要更改源代码就可以切换到新的工厂。这里也是如此在不修改源码的情况下为某个类增加新的方法也就实现了类的扩展。 2空说无凭我们来看看在C#中是怎么来判断扩展方法的通过智能提示我们发现有一些方法带了一个指向下方的箭头查看温馨提示我们知道他是一个扩展方法。所得是乃原来我们一直对集合进行筛选的Where()方法居然是扩展方法而不是原生的。 我们再来看看使用Where这个扩展方法的代码示例 staticvoid UseExtensionMethod() {ListPerson personList new ListPerson(){
new Person(){ID1,NameBig Yellow,Age10}, new Person(){ID2,NameLittle White,Age15}, new Person(){ID3,NameMiddle Blue,Age7} };// 下面就使用了IEnumerable的扩展方法Wherevar datas personList.Where(delegate(Person p) {
return p.Age 10; });foreach (var data in datas) {Console.WriteLine({0}-{1}-{2}, data.ID, data.Name, data.Age);}} 上述代码使用了Where扩展方法找出集合中Age10的数据形成新的数据集并输出 3既然扩展方法是为了对类进行扩展那么我们可不可以进行自定义扩展呢答案是必须可以。我们先来看看扩展方法是如何的定义的可以通过刚刚的IEnumerable接口中的Where方法定义来看看有哪些规则通过 转到定义 的方式我们可以看到在System.Linq命名空间下有叫做Enumerable的这样一个静态类它的成员方法全是静态方法而且每个方法的大部分第一参数都是以this开头。于是我们可以总结出扩展方法的三个要素是静态类、静态方法以及this关键字。 publicstatic class Enumerable {
publicstatic IEnumerableTSource UnionTSource(this IEnumerableTSource first, IEnumerableTSource second, IEqualityComparerTSource comparer); } 那么问题又来了为何一定得是static静态的呢这个我们都知道静态方法是不属于某个类的实例的也就是说我们不需要实例化这个类就可以访问这个静态方法。所以你懂的啦。 4看完扩展方法三要素我们就来自动动手写一个扩展方法 publicstatic class PersonExtension {
publicstatic string FormatOutput(this Person p) {
returnstring.Format(ID:{0},Name:{1},Age:{2}, p.ID, p.Name, p.Age);}} 上面这个扩展方法完成了一个格式化输出Person对象属性信息的字符串构造可以完成上面例子中的输出效果。于是我们可以将上面的代码改为以下的方式进行输出 staticvoid UseMyExtensionMethod() {ListPerson personList new ListPerson(){
new Person(){ID1,NameBig Yellow,Age10}, new Person(){ID2,NameLittle White,Age15}, new Person(){ID3,NameMiddle Blue,Age7} };var datas personList.Where(delegate(Person p) {
return p.Age 10; });foreach (var data in datas) {Console.WriteLine(data.FormatOutput());}} 3.2 嗦嘎—探秘扩展方法 刚刚我们体验了扩展方法的神奇之处现在我们本着刨根究底的学习态度借助Reflector看看编译器到底帮我们做了什么工作 1通过反编译刚刚那个UseMyExtensionMethod方法我们发现并没有什么奇怪之处。 2这时我们可以将C#切换到IL代码看看或许会有另一番收获于是果断切换之后发现了真谛 原来编译器在编译时自动将Person.FormatOutput更改为了PersonExtension.FormatOutput这时我们仿佛茅塞顿开所谓的扩展方法原来就是静态方法的调用而已所德是乃原来如此于是我们可以将这样认为person.FormatOutput() 等同于调用 PersonExtension.FormatOutput(person); 3再查看所编译生成的方法发现this关键已经消失了。我们不禁一声感叹原来this只是一个标记而已标记它是扩展的是哪一个类型在方法体中可以对这个类型的实例进行操作。 3.3 注意—总结扩展方法 1如何定义扩展方法 定义静态类并添加public的静态方法第一个参数 代表 扩展方法的扩展类。 a) 它必须放在一个非嵌套、非泛型的静态类中(的静态方法); b) 它至少有一个参数; c) 第一个参数必须附加 this 关键字; d) 第一个参数不能有任何其他修饰符out/ref e) 第一个参数不能是指针类型 2当我们把扩展方法定义到其它程序集中时一定要注意调用扩展方法的环境中需要包含扩展方法所在的命名空间 3如果要扩展的类中本来就有和扩展方法的名称一样的方法到底会调用成员方法还是扩展方法呢 答案编译器默认认为一个表达式是要使用一个实例方法但如果没有找到就会检查导入的命名空间和当前命名空间里所有的扩展方法并匹配到适合的方法。 http://www.cnblogs.com/edisonchou/p/4088959.html 1.1 初识Action MSDN给出的定义封装一个方法该方法不具有参数并且不返回值。 可以使用此委托以参数形式传递方法而不用显式声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说封装的方法不得具有参数并且不得返回值。在 C# 中该方法必须返回 void通常这种方法用于执行某个操作。 现在我们来看看如何使用Action委托 1先看看之前我们是怎么来使用无返回值委托的例子 View Code 可以清楚地看出我们之前要先显式声明了一个名为 ShowValue 的委托并将对 Name.DisplayToWindow 实例方法的引用分配给其委托实例。 2再看看有了Action委托之后我们怎么来达到上面的效果的例子 View Code 可以清楚地看出现在使用 Action 委托时不必显式定义一个封装无参数过程的委托。 1.2 深入Action 在实际开发中我们经常将一个委托实例作为一个方法的参数进行传递于是我们来看一下这个典型的场景再通过Reflector反编译工具查看编译器到底帮我们做了什么好玩的事儿 1首先来看一下在List集合类型的ForEach方法的定义 //// 摘要:// 对 System.Collections.Generic.ListT 的每个元素执行指定操作。 //// 参数:// action:// 要对 System.Collections.Generic.ListT 的每个元素执行的 System.ActionT 委托。 //// 异常:// System.ArgumentNullException:// action 为 null。publicvoid ForEach(ActionT action); 可以看出ForEach方法的参数是一个Action委托实例也就是说是一个无返回值的委托实例。 2定义一个实体类并通过Action委托使用ForEach方法 View Code 可以看出我们为ForEach方法传递了一个Action委托的实例本质上是一个无返回值的方法指针遍历输出了每个Person对象的信息。 3也许有些童鞋看到上面的还是有点不解只要你了解过委托那么我们可以通过Reflector反编译工具去看看编译器到底做了啥事Action委托的本质就会一如了然这里我们可以先看看没有Action的做法是不是需要首先显式声明了一个无返回值的委托然后是不是还要顶一个命名的无返回值的方法 ①将编译好的程序集拖动到Reflector中可以看到以下的情形 ②现在分别看看编译器为我们自动生成的无返回值的委托定义和方法定义 可以看出不管是自动生成的委托还是方法都是不带返回值的。 ③有了上面的分析我们再来看看执行的语句是怎么被编译的 可以看出在编译后的代码里边连new ActionPerson()都省掉了我们也可以知道在代码中可以更加简化。但是首先我们得了解到底编译器是怎么识别Action委托的。于是按照前两篇的思路在反编译后的C#代码看不出什么端倪的时候切换到IL代码一探究竟 由IL代码可以看出还是原来的方法还是原来的味道。委托还是那个委托执行委托还是执行那个方法。这里我们再来看看List类型的ForEach方法是怎么使用Action委托的 现在我们可以知道原来所不解的东西现在终于释怀了在ForEach会通过一个循环遍历依次调用委托所持有的方法这个方法是一个符合Action委托定义的无返回值方法。至于为什么我们可以省略new ActionT()则是编译器为我们提供的一个便利。例如我们在使用ListPerson对象的ForEach方法时我们可以这样写 personList.ForEach(delegate(Person p)
{Console.WriteLine(p.ID - p.Name - p.Age); }); 首先由于我们是使用的personList这个对象ListPerson类型所以编译器自动识别了泛型委托的T即指定类型为Person。其次编译器自动将无返回值的匿名方法转换为了new ActionPerson对象。当然如果是有返回值的匿名方法则会转换为指定类型的new FuncT()对象这里因为ForEach只接受无参数的委托实例或方法所以如果传入了有返回值的匿名方法则会报错。 1.3 你究竟有几个Action可用 从图中可以看出.NET Framework为我们提供了多达16个参数的Action委托定义对于常见的开发场景已经完全够用了。 二、有返回类型的内置委托—Func 2.1 初识Func MSDN给出的定义封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。 此委托的定义如下 publicdelegate TResult Funcin T, out TResult(T arg) 1in T 此委托封装的方法的参数类型。 2out TResult 此委托封装的方法的返回值类型。 可以使用此委托表示一种能以参数形式传递的方法而不用显式声明自定义委托。封装的方法必须与此委托定义的方法签名相对应。也就是说封装的方法必须具有一个通过值传递给它的参数并且必须返回值。 2.1.1 没有Func时的使用 View Code 2.1.2 有了Func后的使用 View Code 当然我们还可以借助匿名方法更加便捷地使用 View Code 可以清楚地看出现在使用 Func 委托时不必显式定义一个新委托并将命名方法分配给该委托。 2.2 深入Func 2.2.1 用法先行爽一下 我们已经知道Func委托是带指定返回值类型的委托那么我们来看看在实际开发场景的一幕。还是以刚刚那个数据集合PersonList为例在很多时候我们需要对从数据库中读取的数据集合进行二次筛选这时我们可以使用List集合的Select方法我们将一个Func委托实例作为方法参数传递给Select方法就可以返回一个符合我们指定条件的新数据集合。 1先来看看Select方法的定义 //// 摘要:// 将序列中的每个元素投影到新表中。 //// 参数:// source:// 一个值序列要对该序列调用转换函数。 //// selector:// 应用于每个元素的转换函数。 //// 类型参数:// TSource:// source 中的元素的类型。 //// TResult:// selector 返回的值的类型。 //// 返回结果:// 一个 System.Collections.Generic.IEnumerableT其元素为对 source 的每个元素调用转换函数的结果。 //// 异常:// System.ArgumentNullException:// source 或 selector 为 null。publicstatic IEnumerableTResult SelectTSource, TResult(this IEnumerableTSource source, FuncTSource, TResult selector); 可以看出Select方法中的参数采用了Func泛型委托根据泛型委托的定义TSource和TResult分别代表要传入的数据类型以及要返回的数据类型。 2再来看看如何在程序中使用Func委托 首先定义一个与源数据类型不同的新数据类型作为返回值类型 publicclass LitePerson {
publicstring Name { get; set; } } ①标准定义版 ListPerson personList GetPersonList();IEnumerableLitePerson litePersonList personList.SelectPerson, LitePerson(
new FuncPerson, LitePerson(
delegate(Person p){
returnnew LitePerson() { Name p.Name }; })); ②嘻哈简化版借助编译器提供的自动识别简化我们的代码 IEnumerableLitePerson litePersonList personList.Select(
delegate(Person p){
returnnew LitePerson() { Name p.Name }; }); ③绝逼懒人版借助匿名类和泛型可以大大简化我们的代码 var liteList personList.Select(delegate(Person p) {
returnnew { Name p.Name, AddDate DateTime.Now }; }); 3调试运行可以得到以下结果 2.2.2 原理为王探一次 1通过Reflector反编译我们再来看看编译器帮我们生成的东东 2看看自动生成的委托和方法的定义 相信经过上节Action的详细分析这里大家应该也可以举一反三了解编译器帮我们到底做了什么事儿了这里我就不再赘述了后面也不会再赘述此方面的东东为了节省页面大小。 当然和Action类似.NET基类库为我们也提供了多达16个输入参数的Func委托但是输出参数却只有1个。 三、返回bool类型的内置委托—Predicate 3.1 初识Predicate 经过了Func的了解我们可以知道接下来的这两个Predicate和Comparison其实都属于有返回值类型的委托他们不过是两个具体的特殊实例而已一个返回bool类型一个返回int类型。 MSDN给出的定义表示定义一组条件并确定指定对象是否符合这些条件的方法。 它的定义很简单这里就不再对其进行解释了 publicdelegate bool Predicatein T(T obj) 此委托由 Array 和 ListT 类的几种方法使用常用于在集合中搜索元素。 3.2 深入Predicate 由于Predicate委托常用于在集合中搜索元素那么我们就来看看如何使用Predicate委托来进行元素的搜索。于是我们将目光转到List集合的FindAll方法相信大部分童鞋都用过这个方法。 1先来看看FindAll的定义 //// 摘要:// 检索与指定谓词定义的条件匹配的所有元素。 //// 参数:// match:// System.PredicateT 委托用于定义要搜索的元素应满足的条件。 //// 返回结果:// 如果找到则为一个 System.Collections.Generic.ListT其中包含与指定谓词所定义的条件相匹配的所有元素否则为一个空 // System.Collections.Generic.ListT。 //// 异常:// System.ArgumentNullException:// match 为 null。public ListT FindAll(PredicateT match); 2再来看看FindAll的实现 3现在我们来用一下Predicate委托还是以那个PersonList集合为例假如我们要筛选出Age20的Person我们就可以使用FindAll方法。现在我们来写一下这个委托后面我们会用Lambda表达式来简写那才叫一个爽可以看出关键点在于delegate(Person p) { return p.Age 20; }这一句上传入参数是Person类型的对象返回的是一个比较结果即bool值。 View Code 四、返回int类型的内置委托—Comparison 4.1 初识Comparison MSDN给出的定义表示比较同一类型的两个对象的方法。 它的定义也很简单 publicdelegate int Comparisonin T(T x, T y) T是要比较的对象的类型而返回值是一个有符号整数指示 x 与 y 的相对值如下表所示 值含义小于 0x 小于 y。0x 等于 y。大于 0x 大于 y。 此委托由 Array 类的 SortT(T[], ComparisonT) 方法重载和 ListT 类的 Sort(ComparisonT) 方法重载使用用于对数组或列表中的元素进行排序。 4.2 深入Comparison 由于Comparison委托常用于在集合中进行排序那么我们就来看看如何使用Comparison委托来进行元素的排序。于是我们将目光转到List集合的Sort方法相信大部分童鞋也都用过这个方法。 1老惯例还是先看看Sort方法的定义 //// 摘要:// 使用指定的 System.ComparisonT 对整个 System.Collections.Generic.ListT 中的元素进行排序。 //// 参数:// comparison:// 比较元素时要使用的 System.ComparisonT。 //// 异常:// System.ArgumentNullException:// comparison 为 null。 //// System.ArgumentException:// 在排序过程中comparison 的实现会导致错误。例如将某个项与其自身进行比较时comparison 可能不返回 0。publicvoid Sort(ComparisonT comparison); 2再来看看Sort方法的实现 可以看出这里虽然使用Comparison委托但最终还是转换成了Comparer比较器再次调用重载的Array.Sort静态方法进行排序。 3现在我们来用一下Comparison委托还是以那个PersonList集合为例假如我们要以Age为条件进行降序排列我们应该怎么来写这个委托呢 View Code 实现的效果如下图所示 那么如果是要进行升序排列呢只需要改一下return p2.Age-p1.Age; 更改一下被减数和减数的位置即可完成升序和降序的切换。 View Code 五、Lambda表达式[ C# 3.0/.NET 3.x 新增特性 ] 回顾发现上面的代码需要传一个 匿名方法 写起来特别别扭。于是我们很想知道能否有简化的语法呢微软告诉咱们Of Course必须有它就是Lambda表达式。Lambda表达式是比匿名方法更简洁的一种匿名方法语法。 Lambda来源1920年到1930年期间数学家Alonzo Church等人发明了Lambda积分。Lambda积分是用于表示函数的一套系统它使用希腊字母Lambdaλ来表示无名函数。近年来函数式编程语言如Lisp使用这个术语来表示可以直接描述函数定义的表达式表达式不再需要有名字了。 5.1 初识Lambda表达式 5.1.1 Lambda表达式要点 ①Lambda表达式中的参数列表参数数量、类型和位置必须与委托相匹配 ②表达式中的参数列表不一定需要包含类型除非委托有ref或out关键字此时必须显示声明 ③如果没有参数必须使用一组空的圆括号 5.1.2 Lambda使用示例 View Code 调试运行的结果如下 5.1.3 Lambda本质探析 1以上述案例中的Sort方法为例personList.Sort((p1, p2) p1.Age - p2.Age); 2通过反编译工具可以看到其实是声明了一个Comparison委托实例 3现在我们来分析一下具体的步凑有了前面的基础现在再来看就轻松了许多So Easy! ①编译器自动生成了一个Comparison委托 ②编译器帮我们创建了一个符合Comparison委托签名的静态方法 ③实例化Comparison委托变量并将方法指针传入该委托 ④调用ListT实例的Sort方法并传入Comparison委托实例 其中前面两步①和②可以通过反编译后的C#代码获知而后面两步③和④则需要通过IL代码来分析前面已经介绍过相关这里就不再赘述。 5.2 回顾Lambda进化史 前面了解了Lambda是什么这里我们来回顾一下Lambda的演化过程。 从演化过程可以知道编译器在越来越智能地帮我们做着更多的事儿而我们却在享受着编译器带来的便利沉浸在高效的开发效率中变得越来越懒了。 5.3 语句Lambda Lambda表达式有两种类型一是Lambda表达式二是语句Lambda。 那么语句Lambda和表达式Lambda到底有何区别 ANSWER语句Lambda 和 表达式Lambda 的区别在于前者在 右边有一个语句块(大括号)而后者只有一个表达式(没有return 和大括号)。 EXAMPLES 1表达式Lambda list.FindAll(d d.Id 2);// goes to list.ForEach(d Response.Write(d.ToString() br/));2语句Lambda list.ForEach(d { if (d.Id 2) { Response.Write(d.ToString() br/); } }); 可以看出语句Lambda的右侧有一个语句块在这个大括号内的语句可能会有多条。 http://www.cnblogs.com/edisonchou/p/4104612.html 标准查询运算符提供了包括筛选、投影、聚合、排序等功能在内的查询功能其本质是定义在System.Linq.Enumerable类中的50多个为IEnumerableT准备的扩展方法。 从上图可以看出在Enumerable类中提供了很多的扩展方法这里我们选择其中几个最常用的方法来作一点介绍使我们能更好地利用它们。首先我们需要一点数据来进行演示 View Code 1.1 筛选高手Where方法 Where方法提供了我们对于一个集合的筛选功能但需要提供一个带bool返回值的筛选器匿名方法、委托、Lambda表达式均可从而表明集合中某个元素是否应该被返回。这里我们以上面的数据为例筛选出集合中所有性别为男年龄大于20岁的子集合借助Where方法实现如下 staticvoid SQOWhereDemo() {ListPerson personList GetPersonList();ListPerson maleList personList.Where(p p.Gender true p.Age 20).ToList(); maleList.ForEach(m Console.WriteLine(m.ToString()));} 1运行结果如下图所示 2由本系列文章的第二篇可知扩展方法的本质是在运行时调用扩展类的静态方法而我们写的Lambda表达式在编译时又会被转为匿名方法准确地说应该是预定义泛型委托实例作为方法参数传入扩展方法中最后调用执行该扩展方法生成一个新的List集合返回。 1.2 投影大牛Select方法 Select方法可以查询投射返回新对象集合。这里假设我们先筛选出所有男性集合再根据男性集合中所有项的姓名生成子集合这是一个不同于原类型的类型就可以借助Select方法来实现。 staticvoid SQOSelectDemo() {ListPerson personList GetPersonList();ListLitePerson liteList personList.Where(p p.Gender true).Select(p new LitePerson() { Name p.Name }).ToList();liteList.ForEach(p Console.WriteLine(p.ToString()));} 1运行结果如下图所示 2这里也可以采用匿名类可以省去事先声明LitePerson类的步凑但需要配合var使用 var annoyList personList.Where(p p.Gender true).Select(p new { Name p.Name }).ToList(); 3这里因为实现LitePerson类重写了ToString()方法所以这里直接调用了ToString()方法。 1.3 排序小生OrderBy方法 说到排序我们马上想起了SQL中的order by语句而标准查询运算符中也为我们提供了OrderBy这个方法值得一提的就是我们可以进行多条件的排序因为OrderBy方法返回的仍然是一个IEnumerableT的类型仍然可以继续使用扩展方法。但要注意的是第二次应该使用ThenBy方法。 staticvoid SQOOrderByDemo() {ListPerson personList GetPersonList();
// 单条件升序排序 Console.WriteLine(Order by Age ascending:);ListPerson orderedList personList.OrderBy(p p.Age).ToList();orderedList.ForEach(p Console.WriteLine(p.ToString()));
// 单条件降序排序 Console.WriteLine(Order by Age descending:);orderedList personList.OrderByDescending(p p.Age).ToList();orderedList.ForEach(p Console.WriteLine(p.ToString()));
// 多条件综合排序 Console.WriteLine(Order by Age ascending and ID descending:);orderedList personList.OrderBy(p p.Age).ThenByDescending(p p.ID).ToList();orderedList.ForEach(p Console.WriteLine(p.ToString()));} 运行结果如下图所示 1.4 连接道士Join方法 在数据库中我们对两个表或多个表进行连接查询时往往会用到join语句然后指定两个表之间的关联关系例如 a.bid b.aid。在标准查询运算符中细心的.NET基类库也为我们提供了Join方法。现在假设我们有两个类Person和Children其中每个Children对象都有一个ParentID对应Person对象的ID现需要打印出所有Person和Children的信息可以借助Join方法来实现。 staticvoid SQOJoinDemo() {ListPerson personList GetPersonList();ListChildren childrenList GetChildrenList();// 连接查询var joinedList personList.Join(childrenList,p p.ID, c c.ParentID, (p, c) new {ParentID p.ID,ChildID c.ChildID,ParentName p.Name,ChildName c.ChildName}).ToList();joinedList.ForEach(c Console.WriteLine(c.ToString()));} 运行结果如下图所示 1.5 分组老师GroupBy方法 在数据库中我们要对查询结果进行分组会用到 group by 语句在标准查询运算符中我们也有对应的GroupBy方法。这里假设我们对Person数据集按照性别进行分类该怎么来写代码呢 staticvoid SQOGroupByDemo() {ListPerson personList GetPersonList();IEnumerableIGroupingbool, Person groups personList.GroupBy(p p.Gender);IListIGroupingbool, Person groupList groups.ToList();foreach (IGroupingbool, Person group in groupList) {Console.WriteLine(Group:{0}, group.Key ? 男 : 女);
foreach (Person p in group) {Console.WriteLine(p.ToString());}}} 1这里需要注意的是通过GroupBy方法后返回的是一个IEnumerableIGroupingTKey, TSource类型其中TKey是分组依据的类型这里是根据Gender来分组的而Gender又是bool类型所以TKey这里为bool类型。TSource则是分组之后各个元素的类型这里是将ListPerson集合进行分组因此分完组后每个元素都存储的是Person类型所以TSource这里为Person类型Do you understand now? 2运行结果如下图所示 3可能有人会说我咋记得住GroupBy返回的那个类型太长了我也不想记。怎么办呢不怕我们可以使用var关键字嘛 var annoyGroups personList.GroupBy(p p.Name).ToList();
foreach (var group in annoyGroups) {Console.WriteLine(Group:{0}, group.Key);
foreach (var p in group) {Console.WriteLine(p.ToString());}} 1.6 分页实战Skip与Take方法 相信很多人都使用过标准查询运算符进行分页操作这里我们再次来看看如何借助Skip与Take方法来实现分页操作。还是以PersonList集合为例假如页面上的表格每页显示5条数据该怎么来写代码呢 staticvoid SQOPagedDemo() {
// 这里假设每页5行数据 // 第一页 Console.WriteLine(First Page:);
var firstPageData GetPagedListByIndex(1, 5); firstPageData.ForEach(d Console.WriteLine(d.ToString()));
// 第二页 Console.WriteLine(Second Page:);
var secondPageData GetPagedListByIndex(2, 5); secondPageData.ForEach(d Console.WriteLine(d.ToString()));
// 第三页 Console.WriteLine(Third Page:);
var thirdPageData GetPagedListByIndex(3, 5); thirdPageData.ForEach(d Console.WriteLine(d.ToString()));}static ListPerson GetPagedListByIndex(int pageIndex, int pageSize) {ListPerson dataList GetMorePersonList();
return dataList.Skip((pageIndex - 1) * pageSize) .Take(pageSize).ToList();} 运行结果如下图所示 1.7 浅谈延迟加载与即时加载 1延迟加载Lazy Loading只有在我们需要数据的时候才去数据库读取加载它。 在标准查询运算符中Where方法就是一个典型的延迟加载案例。在实际的开发中我们往往会使用一些ORM框架例如EF去操作数据库Where方法的使用则是每次调用都只是在后续生成SQL语句时增加一个查询条件EF无法确定本次查询是否已经添加结束所以没有办法木有办法在每个Where方法执行的时候确定最终的SQL语句只能返回一个DbQuery对象当使用到这个DbQuery对象的时候才会根据所有条件生成最终的SQL语句去查询数据库。 var searchResult personList.Where(p p.Gender false).Where(p p.Age 20) .Where(pp.Name.Contains(奶茶)); 2即时加载Eager Loading在加载数据时就把该对象相关联的其它表的数据一起加载到内存对象中去。 在标准查询运算符中FindAll方法就是一个典型的即时加载案例。与延迟加载相对应在开发中如果使用FindAll方法EF会根据方法中的条件自动生成SQL语句然后立即与数据库进行交互获取查询结果并加载到内存中去。 var searchResult personList.FindAll(pp.Gender false p.Name.Contains(奶茶));二、查询方式谁更快LINQ[ C# 3.0/.NET 3.x 新增特性 ] 2.1 初识LINQ类似SQL风格的代码 LINQ又称语言集成查询它是C# 3.0的新语法。在更多的人看来它是一种方便的查询表达式或者说是和SQL风格接近的代码。 var maleList from p in personList where p.Gender true select p; 1LINQ表达式以from开始以select 或 group by子句结尾 2LINQ表达式的输出是一个 IEnumerableT 或 IQueryableT 集合注T 的类型 由 select 或 group by 推断出来 2.2 LINQ使用实现除Skip和Take外的标准查询运算符的功能 1基本条件查询 ListPerson personList GetPersonList();ListChildren childList GetChildrenList();
// 基本条件查询 Console.WriteLine(Basic Query:);
var maleList from p in personList where p.Gender true select p;maleList.ToList().ForEach(m Console.WriteLine(m.ToString())); 2排序条件查询 // 排序条件查询 Console.WriteLine(Order Query:);
var orderedList from p in personList orderby p.Age descending
orderby p.Name ascending
select p;orderedList.ToList().ForEach(m Console.WriteLine(m.ToString())); 3连接查询 // Join连接查询 Console.WriteLine(Join Query:);
var joinedList from p in personList join c in childListon p.ID equals c.ParentID
selectnew {Person p,Child c};
foreach (var item in joinedList) {Console.WriteLine(item.ToString());} 4分组查询 // 分组条件查询 Console.WriteLine(Group Query:);
var groupList from p in personList group p by p.Gender;
foreach (var group in groupList) {Console.WriteLine(Group:{0}, group.Key? 男:女);
foreach(var item in group) {Console.WriteLine(item.ToString());}} 运行结果请参考上一节标准查询运算符中相关的运行结果或下载附件运行查看这里不再贴图。 2.3 LINQ本质生成对应的标准查询运算符 作为一个细心的.Net码农我们不由得对LINQ表达式为我们做了哪些工作而好奇于是我们又想起了我们的滑板鞋—Reflector或ILSpy去看看编译器为我们做了什么事 1以上述的基本条件查询代码为例我们看到原来编译器将LINQ生成了对应的标准查询运算符即Where扩展方法 2再来看看排序条件查询的代码也是生成了对应的标准查询运算符即OrderBy扩展方法 3总结LINQ编译后会生成对应的标准查询运算符查询-Where排序-OrderBy连接-Join分组-GroupBy所以LINQ表达式其实就是类似于SQL风格的一种更加友好的语法糖而已。其本质还是扩展方法、泛型委托等旧酒被一个新瓶子所包装了起来就变得高大上了。 系列总结 转眼之间四篇文章的介绍就到此结束了其实本系列介绍的都是不算新语法其实也可以说成是老语法了。说它们新只不过是相对于.NET老版本而言而且平时开发中大家有可能没有注意到的一些细节本系列做了一个简单的介绍。这几天看到很多园子里的童鞋开始关注C# 6.0的新特性了粗略看了看语法糖居多相信经过了这一系列的探秘对于新的语法糖我们可以站在一个比较高的高度去看待它们。最后谢谢各位园友的浏览以及给我的一些鼓励再次感谢 http://www.cnblogs.com/edisonchou/p/4109465.html转载于:https://www.cnblogs.com/matsn/p/6973047.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87872.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!