CLR NET 45 基类库中的新增功能.docx
- 文档编号:30702473
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:15
- 大小:57.44KB
CLR NET 45 基类库中的新增功能.docx
《CLR NET 45 基类库中的新增功能.docx》由会员分享,可在线阅读,更多相关《CLR NET 45 基类库中的新增功能.docx(15页珍藏版)》请在冰豆网上搜索。
CLRNET45基类库中的新增功能
.NET4.5基类库中的新增功能
ImmoLandwerth
Microsoft.NETFramework基类库(BCL)中包含的全都是基本类。
虽然有些基本结构很稳定而不会发生多大变化(如System.Int32和System.String),但Microsoft还是在这方面投入了很多人力和物力。
本文介绍了.NETFramework4.5中对BCL进行的重大改进(以及一些很小的改进)。
在阅读本文时,请记住本文以.NETFramework4.5测试版为基础,而不是以最终产品和API为基础,因此,功能可能会有所变化。
如果您希望简要了解.NETFramework中的其他方面(如WindowsCommunicationFoundation(WCF)或WindowsPresentationFoundation(WPF)),请参阅MSDN库页面“.NETFramework4.5测试版中的新增功能”(bit.ly/p6We9u)。
简化的异步编程
使用异步I/O有很多优点。
这有助于避免阻止UI,并且可以减少操作系统需要使用的线程数。
然而,您很可能无法利用该功能,因为异步编程过去一直相当复杂。
最大的问题是,以前的异步编程模型(APM)是围绕Begin/End方法对设计的。
为了说明这种模式的工作原理,请考虑使用下面的简单同步方法来复制流:
1publicvoidCopyTo(Streamsource,Streamdestination)
2{
3byte[]buffer=newbyte[0x1000];
4intnumRead;
5while((numRead=source.Read(buffer,0,buffer.Length))!
=0)
6{
7destination.Write(buffer,0,numRead);
8}
9}
要将这种方法变为使用较早APM的异步方法,您必须编写图1中所示的代码。
图1使用旧异步方法复制流
10publicvoidCopyToAsyncTheHardWay(Streamsource,Streamdestination)
11{
12byte[]buffer=newbyte[0x1000];
13Action
14readWriteLoop=iar=>
15{
16for(boolisRead=(iar==null);;isRead=!
isRead)
17{
18switch(isRead)
19{
20casetrue:
21iar=source.BeginRead(buffer,0,buffer.Length,
22readResult=>
23{
24if(readResult.CompletedSynchronously)return;
25readWriteLoop(readResult);
26},null);
27if(!
iar.CompletedSynchronously)return;
28break;
29casefalse:
30intnumRead=source.EndRead(iar);
31if(numRead==0)
32{
33return;
34}
35iar=destination.BeginWrite(buffer,0,numRead,
36writeResult=>
37{
38if(writeResult.CompletedSynchronously)return;
39destination.EndWrite(writeResult);
40readWriteLoop(null);
41},null);
42if(!
iar.CompletedSynchronously)return;
43destination.EndWrite(iar);
44break;
45}
46}
47};
48readWriteLoop(null);
49}
显然,异步版本并不像同步方法那样易于理解。
人们很难从样板代码中了解编程意图;在涉及委托时,需要使用该代码以使基本编程语言结构(如循环)能够正常工作。
如果您没有被困难所吓倒,请尝试添加异常处理和取消。
所幸的是,此BCL版本提供了基于Task和Task
通过添加async和await关键字,C#和VisualBasic提供了极佳的语言支持(顺便说一下,F#已通过异步工作流为其提供语言支持,事实上,此功能的灵感就来源于此)。
因此,编译器现在承担了样板代码的大多数工作(即便不是全部),而过去您必须得自己编写这些代码。
新的语言支持再加上.NETFramework中添加的某些API,可以使编写异步方法差不多与编写同步代码一样简单。
您可以自己试试看,要将CopyTo方法变为异步方法,现在只需要进行下面突出显示的更改:
50publicasyncTaskCopyToAsync(Streamsource,Streamdestination)
51{
52byte[]buffer=newbyte[0x1000];
53intnumRead;
54while((numRead=await
55source.ReadAsync(buffer,0,buffer.Length))!
=0)
56{
57awaitdestination.WriteAsync(buffer,0,numRead);
58}
59}
对于使用新语言功能的异步编程,还有很多有趣的事情值得一说,但我还是希望把重点放在对BCL和您(BCL使用者)的影响上。
不过,如果您特别好奇,请阅读MSDN库页面“使用Async和Await进行异步编程(C#和VisualBasic)”(bit.ly/nXerAc)。
要创建您自己的异步操作,您需要较低级别的构造块。
根据这些构造块,您可以构建更复杂的方法,如前面介绍的CopyToAsync方法。
该方法只需要将Stream类的ReadAsync和WriteAsync方法作为构造块。
图2列出了BCL中添加的一些最重要的异步API。
图2BCL中的异步方法
类型
方法
System.IO.Stream
ReadAsync
WriteAsync
FlushAsync
CopyToAsync
System.IO.TextReader
ReadAsync
ReadBlockAsync
ReadLineAsync
ReadToEndAsync
System.IO.TextWriter
WriteAsync
WriteLineAsync
FlushAsync
请注意,我们没有添加具有很小粒度的API的异步版本,如TextReader.Peek。
原因是,异步API也会增加一些开销,我们希望防止开发人员误入歧途。
这也意味着,我们明确禁止为BinaryReader或BinaryWriter上的方法提供异步版本。
要使用这些API,我们建议使用Task.Run开始新的异步操作,然后从该操作中使用同步API,而不是为每个方法调用都执行此操作。
一般准则是:
尽可能批量使用异步操作。
例如,如果要使用BinaryReader从流中读取1,000个Int32,最好运行一个任务并等待其同步读取所有1,000个Int32,而不是分别运行并等待1,000个任务(每个任务仅读取一个Int32)。
如果要了解有关编写异步代码的详细信息,我建议您阅读“使用.NET进行并行编程”博客文章(
只读集合接口
长期以来,人们要求提供的BCL功能之一是只读集合接口(不要与不可变的集合相混淆;有关详细信息,请参阅第22页上的“不同的只读集合概念”)。
我们的观点一直是,可以通过可选的功能模式最好地模拟该特定方面(只读)。
在这种模式下,将提供一个API以允许使用者测试是否不支持给定功能和引发NotSupportedException。
这种模式的好处是,它需要较少的类型,因为您不需要模拟功能组合。
例如,Stream类提供了一些功能,所有这些功能都是通过布尔get取值函数(CanSeek、CanRead、CanWrite和CanTimeout)表示的。
这样,BCL仅为流提供一种类型,但仍支持每种流功能组合。
经过很多年的研究,我们得出结论,添加只读集合接口尽管会增加复杂性,但仍然是值得的。
首先,我希望向您介绍这些接口,然后介绍它们提供的功能。
图3显示了现有(可变)集合接口的VisualStudio类图;图4显示了相应的只读接口。
图3可变的集合接口
图4只读集合接口
请注意,IReadOnlyCollection
在测试版中,IReadOnlyList
IEnumerable
这意味着,如果一个方法接受IEnumerable
如果类型层次结构和算法可以应用于特定的类型(例如,可绘制不同形状的应用程序),这是非常有用的。
对于大多数涉及类型集合的情况,使用IEnumerable
60Materialization.IEnumerable
如果算法要求多次迭代访问集合,并且计算序列的开销较大,这可能会导致性能下降;这还可能会产生不易察觉的错误,因为后续迭代再次生成对象时会出现标识不匹配问题。
61Count.IEnumerable
实际上,它可能根本没有计数,因为这可能是一个无穷序列。
在很多情况下,使用静态扩展方法Enumerable.Count就足够了。
首先,它将已知集合类型(如ICollection
不过,根据集合的大小,情况可能会有所不同。
62Indexing.IEnumerable
有些算法(如快速排序)取决于能否通过其索引访问项目。
再者,如果IList
不过,如果在循环中使用索引,线性扫描可能会对性能产生灾难性的影响,因为它将开销不大的O(n)算法变为O(n2)算法。
因此,如果您需要随机访问,您就确实需要随机进行访问。
为什么不直接使用ICollection
这是因为将会失去协变性,并且无法再区分仅读取集合的方法和还会修改集合的方法;通常,在使用异步编程或多线程时,此功能将变得益发重要。
换句话说,您希望鱼与熊掌兼得。
输入IReadOnlyCollection
IReadOnlyCollection
这样,就可以创建算法以表示具体化的集合或具有已知有限大小的集合的需求。
IReadOnlyList
这两个接口是协变的,这意味着,如果一个方法接受IReadOnlyList
63classShape{/*...*/}
64classCircle:
Shape{/*...*/}
65voidLayoutShapes(IReadOnlyList
66voidLayoutCircles()
67{
68List
69LayoutShapes(circles);
70}
糟糕的是,我们的类型系统不允许生成T协变类型,除非它没有将T作为输入的方法。
因此,我们无法将IndexOf方法添加到IReadOnlyList
我们认为,与没有协变支持相比,这点牺牲不算什么。
我们的所有内置集合实现(如数组、List
由于现在可以将任何集合视为只读集合,算法可以更准确地声明其意图,而不会限制其重用级别,可以在所有集合类型中使用它们。
在前面的示例中,LayoutShapes使用者可以传入List
这些集合类型的另一个好处是,它们为使用Windows运行时(WinRT)提供了极佳的体验。
WinRT提供了自己的集合类型,如Windows.Foundation.Collections.IIterable
CLR元数据层将这些类型直接映射到相应的BCL数据类型。
例如,从.NETFramework中使用WinRT时,IIterable
事实上,使用VisualStudio和IntelliSense的开发人员甚至不能觉察到WinRT具有不同的集合类型。
由于WinRT还提供了只读版本(如IVectorView
不同的只读集合概念
▪可变(或非只读)-.NET世界中的最常见集合类型。
这些是允许读取以及添加、删除和更改项目的集合,例如,List
▪只读-这些是无法从外部修改的集合。
不过,此集合概念不保证其内容从不改变。
例如,无法直接更新字典的键和值集合,但添加到字典中将间接更新键和值集合。
▪不可变-这些是在创建后保证永不改变的集合。
对于多线程来说,这是一个很好的属性。
如果复杂的数据结构是完全不可变的,则可以始终安全地将其传递给后台工作线程。
您不必担心有人会同时修改它。
目前,这种集合类型并不是由Microsoft.NETFramework基类库(BCL)提供的。
▪可冻结-这些集合在冻结之前类似于可变集合。
在冻结后,它们类似于不可变集合。
虽然BCL未定义这些集合,但您可以在WindowsPresentationFoundation中找到它们。
AndrewArnott写了一篇极好的博客文章,其中更详细地介绍了不同的集合概念(bit.ly/pDNNdM)。
.zip存档支持
多年以来,另一个常见的需求是常规.zip存档读取和写入支持。
.NETFramework3.0和更高版本支持依照开放打包约定(bit.ly/ddsfZ7)读取和写入存档。
不过,System.IO.Packaging进行了量身定制以支持该特定规范,通常不能用于处理普通.zip存档。
此版本通过System.IO.Compression.ZipArchive添加了极佳的压缩支持。
此外,我们还在DeflateStream实现中解决了长期存在的性能和压缩质量问题。
从.NETFramework4.5开始,DeflateStream类使用常见的zlib库。
因此,它提供了更好的压缩算法实现;大多数情况下,压缩文件比早期版本的.NETFramework小。
要提取磁盘上的整个存档,只需要编写一行代码:
71ZipFile.ExtractToDirectory(@"P:
\files.zip",@"P:
\files");
我们还确保典型操作不需要将整个存档都读取到内存中。
例如,从较大存档中提取单个文件可能如下所示:
72using(ZipArchivezipArchive=
73ZipFile.Open(@"P:
\files.zip",ZipArchiveMode.Read))
74{
75foreach(ZipArchiveEntryentryinzipArchive.Entries)
76{
77if(entry.Name=="file.txt")
78{
79using(Streamstream=entry.Open())
80{
81ProcessFile(stream);
82}
83}
84}
85}
在这种情况下,加载到内存中的唯一部分是.zip存档的目录。
提取的文件是完全流式传输的;即,它不需要加载到内存中。
这样,即使内存很有限,也可以处理任意大的.zip存档。
创建.zip存档的工作原理是类似的。
要从目录中创建.zip存档,您只需编写一行代码:
86ZipFile.CreateFromDirectory(@"P:
\files",@"P:
\files.zip");
当然啦,您也可以手动构造.zip存档,从而使您可以完全控制内部结构。
下面的代码说明了如何创建仅添加C#源代码文件的.zip存档(此外,.zip存档现在还包含一个名为SourceCode的子目录):
87IEnumerable
88Directory.EnumerateFiles(@"P:
\files","*.cs");
89using(ZipArchivezipArchive=
90ZipFile.Open(@"P:
\files.zip",ZipArchiveMode.Create))
91{
92foreach(stringfileinfiles)
93{
94varentryName=Path.Combine("SourceCode",Path.GetFileName(file));
95zipArchive.CreateEntryFromFile(file,entryName);
96}
97}
通过使用流,您还可以构造不通过实际文件支持输入的.zip存档。
这同样适用于.zip存档本身。
例如,您可以使用将流作为输入的ZipArchive构造函数,而不是使用ZipFile.Open。
例如,您可以使用此构造函数构建Web服务器,以便通过数据库中存储的内容动态创建.zip存档,以及将结果直接写入到响应流中,而不是写入到磁盘中。
需要解释一下一个有关API设计的细节。
您可能已注意到,静态简便方法是在ZipFile类上定义的,而实际实例具有ZipArchive类型。
为什么会这样?
从.NETFramework4.5开始,我们在设计API时考虑了可移植性问题。
某些.NET平台不支持文件路径,如用于Windows8上的Metro风格应用程序的.NET。
在此平台上,将通过代理进行文件系统访问以启用基于功能的模型。
要读取或写入文件,您无法再使用常规Win32API;而必须使用WinRTAPI。
正如我向您介绍的一样,.zip功能本身根本不需要文件路径。
因此,我们将该功能分成两个部分:
98System.IO.Compression.dll。
此程序集包含通用.zip功能。
它不支持文件路径。
此程序集中的主类是ZipArchive。
99System.IO.Compression.FileSystem.dll。
此程序集提供ZipFile静态类以定义扩展方法和静态帮助程序。
在支持文件系统路径的.NET平台上,这些API通过简便方法增强了.zip功能。
要了解有关编写可移植的.NET代码的详细信息,请参阅MSDN库中的“可移植的类库”页面(bit.ly/z2r3eM)。
其他改进
当然啦,要介绍的内容还有很多。
在使用一个版本很长时间后,命名最重要的功能有时感觉就像给喜爱的孩子起个名字一样。
下面,我希望重点介绍几个值得一提的方面,但限于本文的篇幅而不能详细进行介绍:
AssemblyMetadataAttribute-我们在.NETFramework中注意到一个有关属性的问题,那就是无论有多少个属性,您都嫌不够多(顺便说一下,.NETFramework4已包含300多个程序集级属性)。
AssemblyMetadataAttribute是一个通用程序集属性,可用于将基于字符串的键值对与程序集相关联。
这可用于指向产品主页或与构建程序集时使用的源文件对应的版本控制标签。
WeakReference
首先,无论何时需要访问目标,它都会强制使用者进行转换。
更重要的是,它有一个设计缺陷,而导致在使用它时很容易出现争用问题:
它公开一个API以检查对象是否处于活动状态(IsAlive),并公开一个单独的API以访问实际对象(Target)。
WeakReference
Comparer
一种方法是通过接口IComparer
将IComparer
大多数语言提供从方法到委派类型的隐式转换,因此,您可以轻松通过IComparer
不过,逆转换要求您自行实现IComparer
在.NETFramework4.5中,我们在Comparer
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- CLR NET 45 基类库中的新增功能 基类库 中的 新增 功能