C#的变迁史03 - C# 3.0篇

C# 3.0 (.NET 3.5, VS2008)

  第三代C#在语法元素基本完备的基础上提供了全新的开发工具和集合数据查询方式,极大的方便了开发。


1. WPF,WCF,WF

  这3个工程类型奠定了新一代.NET开发的客户端模型,通信模型,工作流模型。

  WPF即将取代Winform成为新一代的桌面程序开发工具,控件与代码的超低耦合给开发带来了极大的方便,脱胎于MVC的MVVM模式也展现了极强的生命力。WCF即将融合原来的Web Service的各种提供方式,彻底屏蔽掉各种细节,开启Service服务的篇章。WF似乎使用的比较少,目前不做评论。

  这3个概念每个都可以写上几本书,这里就不出丑了。

 

2. Lambda表达式

  Lambda 表达式是一种可用于创建委托或表达式树类型的匿名函数。 通过使用 lambda 表达式,可以创建可作为参数传递或作为函数调用值返回的本地函数。 Lambda 表达式主战场是 Linq 查询表达式,这个在下面会提及;由于Lambda表达式是创建委托和表达式树的,所以它在除Linq之外的地方使用也很广泛,使用Lambda表达式可以写出相当优雅的委托代码。

  若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。 例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值。

  左侧的参数列表可以带参数类型,也可以不带。指定参数类型时通常是因为右侧的语句块中使用了该类型的相关方法;当不带参数类型的时候,就由编译器根据上下文去推断,推断成立则没问题,推断不成立则编译错误。左侧的参数列表需要带"()",但是当只有一个无类型的参数时可省略。

  右侧的如果是单个表达式的话可以不带"{}"和";",是语句块的话则要加上。

  你可以将此表达式分配给委托类型:

复制代码

delegate int del(int i);
static void Main(string[] args)
{del myDelegate = x => x * x;int j = myDelegate(5); //j = 25
}

复制代码

  当然也可以用于创建表达式树类型:

复制代码

using System.Linq.Expressions;namespace ConsoleApplication1
{class Program{static void Main(string[] args){Expression<del> myET = x => x * x;}}
}

复制代码

  表达式树是一种动态创建表达式的工具,表达式树可以编译和运行;使用它可以动态的创建表达式,它的使用场合主要是在LINQ中区创建动态的查询条件表达式。关于表达式树,有兴趣的同学可以参考MSDN:http://msdn.microsoft.com/zh-cn/library/bb397951.aspx 。

  总的来说,Lambda表达式是基于delegate又高于delegate的东东,青出于蓝而胜于蓝。它更加弱化的约束极大了丰富了表达式的含义,所谓描述越抽象,意义越丰富嘛!难怪抽象派艺术家的作品生命力都很强。在C#中,约束最强的应该就是继承(包括类的继承,接口的实现),它要求子类扩展父类或接口的时候方法时签名要完全匹配,包括返回值类型,函数名,参数类型等;约束次之的是delegate,它不再要求方法名相同了,只要求返回值类型与参数类型相同;到了lambda表达式了,约束更加弱化,连参数与返回值的类型都不要求完全匹配了,难怪有人说如果当初现有lambda表达式的话,就不会有匿名函数的语法了。

 

3. 对象初始化器和集合初始化器

  直接初始化的时候就可以初始化是很方便的事,这个终于有了,虽说是在LINQ中使用最多,但是在其它场合使用对象初始化器和集合初始化器编程还是显得特别优雅。这个比较简单不多说了,看例子:

复制代码

// 基本用法:
User user =new User { Id = 1, Name ="AA", Age = 22 };
//嵌套使用:
User user =new User
{Id = 1,Name ="AA",Age = 22,Address = new Address{City ="NanJing",Zip = 21000}
};
//类似于对象初始化器初始化一个对象,集合初始化器初始化一个集合,
//一句话,有了它你就不用在将元素通过Add逐个添加了:
//基本使用:
List<int> num =new List<int> { 0, 1, 2, 6, 7, 8, 9 };
//结合对象初始化器,我们可以写出如下简洁的代码:
List<User> user =new List<User>{new User{Id=1,Name="AA",Age=22},new User{Id=2,Name="BB",Age=25},
};

复制代码

 

4. 匿名类型

  很多时候,我们需要使用一个临时的对象,按通常的做法,我们要先定义一个类吧,这样才能实例化这个类得到对象,这样实在是太累了;而且往往这样的对象只需要使用在局部的场合,使用以后就不再使用了,例如从数据库中查询出来的临时结果。在3.0中,我们终于不再需要预先定义一个类型了,CLR会提供一种形式让你动态的生成一个无类型的对象。

  匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型。 类型名由编译器生成,并且不能在源代码级使用。 每个属性的类型由编译器推断。

  在看具体的例子之前,先看一个新的关键字:var。这个关键字在Javascript中使用广泛,在C#中使用var声明一个局部变量(只能在函数中使用var定义变量,这种变量官方称之为隐式类型局部变量)时,编译器会自动根据其赋值语句推断这个局部变量的类型。赋值以后,这个变量的类型也就确定而不可以再进行更改。但是这个var关键字最主要的用途是去生成匿名类型,比如表示一个Linq查询的结果。这个结果可能是ObjectQuery<T>或IQueryable<T>类型的对象,也可能是一个简单的实体类型的对象。这时使用var声明这个对象可以节省很多代码书写上的时间。

  看一下匿名类型的使用方式:

var people = new { Name="AA", Age = 10 };
Console.WriteLine(people.Name);

  需要注意的是,上面创建的people的Name和Age是只读的,不能去修改。


5. 扩展方法

  Linq扩展了原来的IEnumerable得到IQueryable,如何自然的融入原来的集合中却是一个问题,有了这个语法糖,只要符合规定的语法,引入定义扩展方法的namespace,新添加的方法就像是对象原来就有的方法那样方便使用,这样就在不破坏原对象封装性的前提下给该对象添加了新的行为,还是蛮符合面向对象Open-Close原则的。

  看网上的一个例子:

复制代码

using System;
using System.Text.RegularExpressions;namespace ConsoleApplication3
{class Program{static void Main(string[] args){string email = "someone@somewhere.com";Console.WriteLine(email.IsValidEmailAddress());}}public static class Extensions{public static bool IsValidEmailAddress(this string s){Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");return regex.IsMatch(s);}}
}

复制代码

  如上代码所示,扩展方法为一静态方法,声明于一个静态类,其参数前加上一个this关键字,参数的类型表示这个扩展方法要对这个类型进行扩展。如上述代码表示其要对字符串类型进行扩展。使用起来也很方便,所有的string类型现在都多了一个叫IsValidEmailAddress的方法。

 

6. Linq 

  当所有的配角都到齐的时候,主角之一的Linq (Language Integrated Query,语言集成查询)应该要亮相了,它是3.0时代最为强悍的工具,从此查询集合数据有了最为便捷的方式,3.0中上面的许多特性基本上都是为了Linq 服务的。

  Linq主要包含4个组件——Linq to Objects、Linq to XML、Linq to DataSet 和Linq to SQL,这4个组件对应4种查询的对象:内存集合中的对象,XML,SQL和Dataset。在我的经历中,我用的最多的是前三个,所以这里主要就是总结前三种查询。

  在Linq之前查询数据,基本的方式就是循环遍历,按照条件比较,把得到的结果放到临时集合中。Linq彻底简化了这个过程,使用了简单的方式完成了查询。不管查询上述的哪些对象,方式其实还都是一样的:要么使用查询表达式,要么使用扩展方法。

  以查询内存集合中的对象为例,看一下两种使用方式:

复制代码

using System.Linq;
List<string> collection = new List<string>();
for (int i = 0; i < 10; i++)
{collection.Add("A" + i.ToString());
}// 创建查询表达式来获得序号为偶数的元素     
var queryResults = from s in collectionlet index = int.Parse(s.Substring(1))where index % 2 == 0select s;// 使用扩展方法来获得序号为偶数的元素     
var queryResults1 = collection.Where(item => {int index = int.Parse(item.Substring(1));return index % 2 == 0;
});
// 输出查询结果     
foreach (string s in queryResults)
{Console.WriteLine(s);
}

复制代码

  查询Xml的方式比较相似,下面来自网上的例子比较了使用原来Class访问Xml的方式,和使用XLinq访问Xml的方式:

复制代码

using System.Xml;
using System.Xml.Linq;static void Main(string[] args)     
{         Console.WriteLine("使用XPath来对XML文件查询,查询结果为:");     OldLinqToXMLQuery();     Console.WriteLine("使用Linq方法来对XML文件查询,查询结果为:");     UsingLinqLinqtoXMLQuery();     Console.ReadKey();      
}       // 初始化XML数据     
private static string xmlString =      "<Persons>"+     "<Person Id='1'>"+     "<Name>张三</Name>"+     "<Age>18</Age>"+     "</Person>" +     "<Person Id='2'>"+     "<Name>李四</Name>"+     "<Age>19</Age>"+     "</Person>"+     "<Person Id='3'>" +     "<Name>王五</Name>" +     "<Age>22</Age>" +     "</Person>"+     "</Persons>";     // 使用XPath方式来对XML文件进行查询     
private static void OldLinqToXMLQuery()     
{     // 导入XML文件     XmlDocument xmlDoc = new XmlDocument();     xmlDoc.LoadXml(xmlString);     // 创建查询XML文件的XPath     string xPath = "/Persons/Person";     // 查询Person元素     XmlNodeList querynodes = xmlDoc.SelectNodes(xPath);     foreach (XmlNode node in querynodes)     {     // 查询名字为李四的元素     foreach (XmlNode childnode in node.ChildNodes)     {     if (childnode.InnerXml == "李四")     {     Console.WriteLine("姓名为: "+childnode.InnerXml + "  Id 为:" + node.Attributes["Id"].Value);     }     }     }             
}     // 使用Linq 来对XML文件进行查询     
private static void UsingLinqLinqtoXMLQuery()     
{     // 导入XML     XElement xmlDoc = XElement.Parse(xmlString);     // 创建查询,获取姓名为“李四”的元素     var queryResults = from element in xmlDoc.Elements("Person")     where element.Element("Name").Value == "李四"select element;     // 输出查询结果     foreach (var xele in queryResults)     {     Console.WriteLine("姓名为: " + xele.Element("Name").Value + "  Id 为:" + xele.Attribute("Id").Value);     }     
} 

复制代码

  需要注意的是使用上面Linq查询得到的结果,只有当使用foreach等方法去遍历的时候查询才会真正的执行并返回结果。

  有的同学很快就发现了,这些关键字怎么看都像是Sql语句的关键字,确实,这就是语言集成查询的真正含义,查询语句可以直接在编译的时候确定语法上正确性,这一点体现最完全的就是Linq to Sql,通常也称为DLinq。Sql基本所有的关键字都可以在C#中找到想对应的关键字,所以Sql基本所有的操作在Linq中都有,比如:查询、排序、分组、增加和删除等等。这个可以通过查询MSDN(http://msdn.microsoft.com/zh-cn/library/bb397676.aspx)或者学习一些优秀的Blog(http://www.cnblogs.com/lifepoem/archive/2011/12/16/2288017.html) 来熟悉其语法。

  在.NET下与数据库交互时,为了从对象级别处理问题,必须对数据库进行抽象的到对应的对象,这个就是ORM(对象关系映射,Object/Relation Mapping)的过程。ORM按照字面的意思理解即可:ORM的过程就是把数据库中的概念,比如数据库,表,字段等,处理成语言中的对象,然后在对象级别上完成数据库的常用操作,这些操作会通关相关的机制自动的反映到数据库中。这是一个抽象的过程,这样做的好处就是处理的程序不用考虑数据库实际操作上的细节,只要在语言层次上完成相关的操作,数据库自然就会被更新。

  在.NET下ORM的手段主要是两种:DLinq和Entity Framework。这两种手段的目标都是一致的,就是ORM的那个过程,但是处理的细节(比如抽象的级别,支持的数据库,支持的程度,是否继续维护等等)有些不同,也就导致了两者不同的命运。总的来说,Entity Framework是重量级的工具,支持多种数据库,特性更多,更加抽象,更加灵活,效率更好一点,而且新版对linq的语法支持也越来越完善(DLinq不再添加新特性了,前途很明显),这真是居家旅行杀人越货必备之首选啊。

  两者的对比网上也很多,比如:http://blog.163.com/kunkun0921@126/blog/static/169204332201401605839384/ 。

  这里想多啰嗦一句的就是Entity Framework支持所谓的Database First和Code First两种开发方式,前置是先设计数据库,后映射对象;后者是先设计对象,后生成数据库。这些开发方式还是相当灵活的,而且在VS的命令行中生成、更新数据库都有相关的命令,使用起来是相当的方便。

 

此外还有一些好的学习网站:

http://www.tuicool.com/topics/11050019

http://www.entlib.net/?cat=31

http://www.cnblogs.com/lsxqw2004/category/266012.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

REVERSE-PRACTICE-BUUCTF-28

REVERSE-PRACTICE-BUUCTF-28[FlareOn6]Memecat Battlestation[b01lers2020]chugga_chugga[INSHack2018]Tricky-Part1[watevrCTF 2019]esreveR[FlareOn6]Memecat Battlestation .Net程序&#xff0c;运行后输入weapon code&#xff0c;用dnSpy打开 在Stage1Form直接找到第一个w…

C#的变迁史04 - C# 4.0 之多线程篇

在.NET 4.0中&#xff0c;并行计算与多线程得到了一定程度的加强&#xff0c;这主要体现在并行对象Parallel&#xff0c;多线程Task&#xff0c;与PLinq。这里对这些相关的特性一起总结一下。 使用Thread方式的线程无疑是比较麻烦的&#xff0c;于是在这个版本中有了改善的版本…

REVERSE-PRACTICE-BUUCTF-29

REVERSE-PRACTICE-BUUCTF-29[FlareOn1]Shellolololol[CFI-CTF 2018]powerPacked[INSHack2018]Tricky-Part2[CFI-CTF 2018]Automated Reversing[FlareOn1]Shellolololol exe程序&#xff0c;直接不能运行&#xff0c;无壳&#xff0c;ida分析 简单F8单步调试发现&#xff0c;在…

C#的变迁史05 - C# 4.0篇

C# 4.0 (.NET 4.0, VS2010) 第四代C#借鉴了动态语言的特性&#xff0c;搞出了动态语言运行时&#xff0c;真的是全面向“高大上”靠齐啊。 1. DLR动态语言运行时 C#作为静态语言&#xff0c;它需要编译以后运行&#xff0c;在编译的过程中&#xff0c;编译器要检查语法的正确性…

REVERSE-PRACTICE-BUUCTF-30

REVERSE-PRACTICE-BUUCTF-30[RCTF2019]DontEatMe[b01lers2020]little_engine[NPUCTF2020]你好sao啊[MRCTF2020]Shit[RCTF2019]DontEatMe exe程序&#xff0c;运行后输入&#xff0c;无壳&#xff0c;用ida分析 交叉引用字符串来到sub_401260函数&#xff0c;读取输入&#xff…

C#的变迁史06 - C# 4.0 之并行处理篇

前面看完了Task对象&#xff0c;这里再看一下另一个息息相关的对象Parallel。 Parallel对象 Parallel对象封装了能够利用多核并行执行的多线程操作&#xff0c;其内部使用Task来分装多线程的任务并试图将它们分配到不同的内核中并行执行。请注意“试图”这个词&#xff0c;Par…

REVERSE-PRACTICE-BUUCTF-31

REVERSE-PRACTICE-BUUCTF-31[羊城杯 2020]login[羊城杯 2020]Bytecode[羊城杯 2020]babyre[ACTF新生赛2020]fungame[羊城杯 2020]login exe程序&#xff0c;运行后输入&#xff0c;无壳&#xff0c;ida分析 没找到主要逻辑&#xff0c;在字符串窗口看到一些“py”的字样&#…

C#的变迁史07 - C# 4.0 之线程安全集合篇

作为多线程和并行计算不得不考虑的问题就是临界资源的访问问题&#xff0c;解决临界资源的访问通常是加锁或者是使用信号量&#xff0c;这个大家应该很熟悉了。 而集合作为一种重要的临界资源&#xff0c;通用性更广&#xff0c;为了让大家更安全的使用它们&#xff0c;微软为我…

PWN-PRACTICE-BUUCTF-1

PWN-PRACTICE-BUUCTF-1test_your_ncripwarmup_csaw_2016ciscn_2019_n_1test_your_nc 附件的main函数直接system("/bin/sh")&#xff0c;nc直接连即可cat flag rip main函数中&#xff0c;gets函数读取一行会造成栈溢出 构造payload覆盖rip&#xff0c;使得return…

C#的变迁史08 - C# 5.0 之并行编程总结篇

C# 5.0 搭载于.NET 4.5和VS2012之上。 同步操作既简单又方便&#xff0c;我们平时都用它。但是对于某些情况&#xff0c;使用同步代码会严重影响程序的可响应性&#xff0c;通常来说就是影响程序性能。这些情况下&#xff0c;我们通常是采用异步编程来完成功能&#xff0c;这在…

REVERSE-PRACTICE-CTFSHOW-1

REVERSE-PRACTICE-CTFSHOW-1逆向签到题re2逆向4逆向5逆向签到题 ida打开即可得到明文flag re2 附件是一个加密过的flag文本和勒索病毒exe 运行程序&#xff0c;输入1&#xff0c;回车&#xff0c;直接退出&#xff0c;ida分析 选项1的逻辑为&#xff0c;打开flag.txt和enfl…

C#的变迁史09 - C# 5.0 之调用信息增强篇

Caller Information CallerInformation是一个简单的新特性&#xff0c;包括三个新引入的Attribute&#xff0c;使用它们可以用来获取方法调用者的信息&#xff0c; 这三个Attribute在System.Runtime.CompilerServices命名空间下&#xff0c;分别叫做CallerMemberNameAttribute&…

REVERSE-PRACTICE-CTFSHOW-2

REVERSE-PRACTICE-CTFSHOW-2re3红包题 武穆遗书数学不及格flag白给re3 main函数&#xff0c;分析可知&#xff0c;将输入的字符串按十六进制转成数字&#xff0c;写到v5&#xff0c;赋给v17[6] 当i等于6时&#xff0c;v16会加上输入的值&#xff0c;然后进入循环&#xff0c;最…

C#的变迁史10 - C# 5.0 之其他增强篇

1. 内置zip压缩与解压   Zip是最为常用的文件压缩格式之一&#xff0c;也被几乎所有操作系统支持。在之前&#xff0c;使用程序去进行zip压缩和解压要靠第三方组件去支持&#xff0c;这一点在.NET4.5中已有所改观&#xff0c;Zip压缩和解压功能已经内置于框架本身。这个功能使…

REVERSE-PRACTICE-CTFSHOW-3

REVERSE-PRACTICE-CTFSHOW-3签退神光签到baby_gay签退 .pyc文件&#xff0c;uncompyle6反编译&#xff0c;得到python源码&#xff0c;分析写在源码注释中 先变表base64&#xff0c;再凯撒加密&#xff0c;向后移动2位 import string c_charset string.ascii_uppercase str…

REVERSE-PRACTICE-CTFSHOW-4

REVERSE-PRACTICE-CTFSHOW-4encodeEasyBJD hamburger competitionJustREencode elf文件&#xff0c;upx脱壳&#xff0c;ida分析 交叉引用字符串"Please input your flag:"&#xff0c;来到sub_804887C函数 输入经过三次变换&#xff0c;先是变表base64&#xff0c;…

CSS 基础框盒模型介绍

当对一个文档进行布局&#xff08;lay out&#xff09;的时候&#xff0c;浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型&#xff08;CSS basic box model&#xff09;&#xff0c;将所有元素表示为一个个矩形的盒子&#xff08;box&#xff09;。CSS 决定这些盒子的大小…

REVERSE-PRACTICE-CTFSHOW-5

REVERSE-PRACTICE-CTFSHOW-5re2_归心Mud[吃鸡杯]ezmore[吃鸡杯]有手就行re2_归心 exe程序&#xff0c;运行后要求输入flag&#xff0c;ida分析 函数窗没找到主逻辑函数&#xff0c;shiftF12看字符串窗口 发现有java/lang/String&#xff0c;com/exe4j/runtime/WinLauncher等字…

PWN-PRACTICE-BUUCTF-2

PWN-PRACTICE-BUUCTF-2pwn1_sctf_2016jarvisoj_level0ciscn_2019_c_1[第五空间2019 决赛]PWN5pwn1_sctf_2016 main函数中执行vuln函数 fgets限制了输入的长度&#xff0c;不足以构成栈溢出 通过将输入中的字符"I"替换成"you"&#xff0c;增加长度&#xf…

PWN-PRACTICE-BUUCTF-3

PWN-PRACTICE-BUUCTF-3[OGeek2019]babyropciscn_2019_n_8get_started_3dsctf_2016jarvisoj_level2[OGeek2019]babyrop 简单的ret2libc&#xff0c;构造rop main函数中读取一个随机数到buf中&#xff0c;传入sub_804871F 用"\x00"来绕过strlen和strncmp&#xff0c;b…