网站导航网学 原创论文 原创专题 网站设计 最新系统 原创论文 论文降重 发表论文 论文发表 UI设计定制 论文答辩PPT格式排版 期刊发表 论文专题
返回网学首页
网学原创论文
最新论文 推荐专题 热门论文 论文专题
当前位置: 网学 > 设计资源 > .Net编程 > 正文

浅谈C#语言的using语句

论文降重修改服务、格式排版等 获取论文 论文降重及排版 论文发表 相关服务

背景知识

外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装入内存的部分,分别把每一部分调入内存完成排序。然后,对已经排序的子文件进行归并排序。

问题提出

假设我们要写一个外部排序程序。现在要讨论的是对已经排序的子文件进行归并排序。

解决方案1

下面是外部排序归并阶段的代码片段:

  1. class ExternalSorting 
  2.   void Merge(string inputFileName1, string inputFileName2, string outputFileName) 
  3.   { 
  4.     using (var reader1 = new StreamReader(inputFileName1)) 
  5.     { 
  6.       using (var reader2 = new StreamReader(inputFileName2)) 
  7.       { 
  8.         using (var writer = new StreamWriter(outputFileName)) 
  9.         { 
  10.           Merge(reader1, reader2, writer); 
  11.         } 
  12.       } 
  13.     } 
  14.   } 
  15.  
  16.   void Merge(TextReader reader1, TextReader reader2, TextWriter writer) 
  17.   { 
  18.     var s1 = reader1.ReadLine(); 
  19.     var s2 = reader2.ReadLine(); 
  20.     while (s1 != null || s2 != null
  21.     { 
  22.       if (Compare(s1, s2) <= 0) StepIt(ref s1, reader1, writer); 
  23.       else StepIt(ref s2, reader2, writer); 
  24.     } 
  25.   } 
  26.  
  27.   int Compare(string s1, string s2) 
  28.   { 
  29.     if (s1 == null && s2 == nullthrow new ArgumentException("s1 和 s2 不能同时为 null"); 
  30.     if (s1 == nullreturn 1; 
  31.     if (s2 == nullreturn -1; 
  32.     return string.Compare(s1, s2); 
  33.   } 
  34.  
  35.   void StepIt(ref string s, TextReader reader, TextWriter writer) 
  36.   { 
  37.     writer.WriteLine(s); 
  38.     s = reader.ReadLine(); 
  39.   } 

上述代码中的第 05 到 14 行的三个 using 语句逐个嵌套,依次缩进,是不是很难看?

注意,上述代码中第 33 行可以替换为你想要的比较大小的方法,以便按照不同的关键字进行排序。

解决方案2

我们知道,可以将多个对象与 using 语句一起使用,但必须在 using 语句中声明这些对象。因此,我们可以将上述的第 05 到 14 行的代码重构如下:

  1. using (TextReader reader1 = new StreamReader(inputFileName1), 
  2.                   reader2 = new StreamReader(inputFileName2)) 
  3.   using (TextWriter writer = new StreamWriter(outputFileName)) 
  4.   { 
  5.     Merge(reader1, reader2, writer); 
  6.   } 

但是还是有两个嵌套的 using 语句,不爽。

解决方案3

我们还知道,C# 编译器实际上将 using 语句转化为 try - finally 块。那么我们继续进行重构:

  1. TextReader reader1 = null
  2. TextReader reader2 = null
  3. TextWriter writer = null
  4. try 
  5.   reader1 = new StreamReader(inputFileName1); 
  6.   reader2 = new StreamReader(inputFileName2); 
  7.   writer = new StreamWriter(outputFileName); 
  8.   Merge(reader1, reader2, writer); 
  9. finally 
  10.   if (reader1 != null) reader1.Dispose(); 
  11.   if (reader2 != null) reader2.Dispose(); 
  12.   if (writer != null) writer.Dispose(); 

这样看起来很不错的样子。注意:

如果上述代码片段不是 Merge 方法中仅有的代码块,请使用一对大括号将其括起来,以便为上述三个对象(reader1、reader2 和 writer)创建有限的范围。

实际上 C# 编译器对解决方案1和解决方案2生成的 IL 代码是差不多的,都是三个嵌套的 try - finally 块。而不是象解决方案3中那样只有一个 try - finally 块。

解决方案4

我们知道 using 语句只不过是提供能确保正确使用 IDisposable 对象的方便语法。using 语句按照正确的方式调用对象上的 Dispose 方法,并会导致在调用 Dispose 时对象自身处于范围之外。因此,可以重构如下:

  1. using (IDisposable reader1 = new StreamReader(inputFileName1), 
  2.                    reader2 = new StreamReader(inputFileName2), 
  3.                    writer = new StreamWriter(outputFileName)) 
  4.   Merge(reader1 as TextReader, reader2 as TextReader, writer as TextWriter); 

这是我最喜欢的方案,你们呢?

解决方案5

但是,解决方案4中第 5 行中使用三个 as 进行强制类型转换毕竟不爽。考虑进行以下重构:

  1. using (TextReader reader1 = new StreamReader(inputFileName1), 
  2.        TextReader reader2 = new StreamReader(inputFileName2), 
  3.        TextWriter writer = new StreamWriter(outputFileName)) 
  4.   Merge(reader1, reader2, writer); 

可惜,上述代码片段无法通过编译,出现以下编译错误:

 CS1044: 在 forusing 和 fixed 或声明语句中不能使用多个类型。

这个编译错误实在是没有道理。实际上在 for、using 和 fixed 语句中能够使用多个类型对程序员来说很有用的,而且 C# 编译器实现这点也没有什么困难。你们以为呢?

解决方案6

好吧,我们换一种方法进行重构:

  1. using (var reader1 = new StreamReader(inputFileName1), 
  2.            reader2 = new StreamReader(inputFileName2), 
  3.            writer = new StreamWriter(outputFileName)) 
  4.   Merge(reader1, reader2, writer); 

非常遗憾,还是无法通过编译。这次的错误信息如下:

CS0819: 隐式类型的局部变量不能有多个声明符。

这个编译错误也是没有道理的。同样,在隐式类型的局部变量中有多个声明符对程序员来说也是很有用的,对 C# 编译器来说也没有什么实现上困难。你们以为呢?

结论

建议修改 C# 编译器,去掉 CS1044 和 CS0819 编译错误,以便允许解决方案5和解决方案6,造福广大 C# 程序员。
对于目前的 C# 编译器,建议使用解决方案4。

  • 下一篇资讯: 总结C#中的数据类型
  • 设为首页 | 加入收藏 | 网学首页 | 原创论文 | 计算机原创
    版权所有 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2020 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号 常年法律顾问:王律师