C#中的异常处理(简单)二

王朝c#·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

三、finally?

解决释放问题的方法依靠你现在使用的语言。在C++中,你可以使用构建于堆栈上的析构函数。Java中,你能构使用finally程序块。C#允许你创造自定义的结构类型但是不允许结构中的析构函数(只是因为一个C#析构函数其实是一个Finally方法,Finally被垃圾回收器调用。结构类,是一种值类型,并不归属于垃圾回收器回收的范围)。因而,只是在开始,C#必须追循Java的道路,使用finally程序块。首先,我们的finally程序块开起来如下:

private static char[] ReadSource(string filename)

{

try

{

FileInfo file = new FileInfo(filename);

int length = (int)file.Length;

char[] source = new char[length];

TextReader reader = file.OpenText();

reader.Read(source, 0, length);

}

finally

{

reader.Close();

}

return source;

}

这个版本不得不引入一个try程序块(既然一个finally程序快必须跟随在一个try程序块后),这将是一个合理的解决方案,如果它奏效的话。但是,它没有做到。问题是try程序块构建成一个范围,所以在finally程序块中的reader并不在这个范围内并且返回语句中的source也不在这个范围。

finally?

为了解决这个问题,你不得不将reader和source的声明移到try程序块的外面,第二次尝试如下:

private static char[] ReadSource(string filename)

{

TextReader reader;

char[] source;

try

{

FileInfo file = new FileInfo(filename);

int length = (int)file.Length;

source = new char[length];

reader = file.OpenText();

reader.Read(source, 0, length);

}

finally

{

reader.Close();

}

return source;

}

这个版本将reader和source的声明移到了try程序块的外面,接着指派给reader和source但没有初始化它们。这是和开始的“理想”版本不同的另外一个地方(出现两个多余行)。然而,你可能认为如果它工作,那将是一个合理的解决方案。但是它没有。问题是委派并不等同于初始化及让编译器知道它。如果在reader被分配之前出现一个异常,这是在finally程序块中对reader.close()的调用

将根据没有被分配的reader,C#,像Java一样,不允许那样。

finally?

很明显,你必须要初始化reader,第三次尝试如下:

private static char[] ReadSource(string filename)

{

TextReader reader = null;

char[] source;

try

{

FileInfo file = new FileInfo(filename);

int length = (int)file.Length;

source = new char[length];

reader = file.OpenText();

reader.Read(source, 0, length);

}

finally

{

reader.Close();

}

return source;

}

这个版本引入了空值,这没有出现在最初的“理想版本”中。不过,如果你仍然认为如果它起作用这将是一个合理的解决方式,然而它不是(虽然它能通过编译)。问题是你在调用reader.close()的时候很容易抛出NullReferenceException异常。

finally?

一种解决方法是对eader.close()方法进行保护,下面做第四次尝试:

private static char[] ReadSource(string filename)

{

TextReader reader = null;

char[] source;

try

{

FileInfo file = new FileInfo(filename);

int length = (int)file.Length;

source = new char[length];

reader = file.OpenText();

reader.Read(source, 0, length);

}

finally

{

if (reader != null)

{

reader.Close();

}

}

return source;

}

当然,对reader.close()的保护并不是ReadSource的理想版本。但是,如果仅从它的效果上看,这将是一个合理的版本。最终,工作。它和最初的版本已经大不相同。稍微努力,你能复用下面这段代码:

private static char[] ReadSource(string filename)

{

FileInfo file = new FileInfo(filename);

int length = (int)file.Length;

char[] source = new char[length];

TextReader reader = file.OpenText();

try

{

reader.Read(source, 0, length);

}

finally

{

if (reader != null)

{

reader.Close();

}

}

return source;

}

在某些情况下,你可以在finally程序块中对可能出现空值进行判断(上面就是一个这样的例子),但是一般说来,你最好还是在finally程序块中判断一下(考虑到如果file.OpenText返回空值,或者如果reader被放进了try程序块中,或者reader作为ref/out参数被传递到try程序块中)。你不得不增加一个try程序块,一个finally程序块,和一个if防护。如果你正在使用Java,你不得不每一次都去做这些事情。在那里是个最大的问题。如果这个解决方案非常令人厌烦且完全偏离于最初的“完美”方案,这没有关系,你能够将这些异常提取到一块。在Java中,你不能这么做。遇到异常,Java将停止运行,而C#则将继续。

四、using语句

在C#中,最接近于“理想”版本的是使用using语句:

private static char[] ReadSource(string filename)

{

FileInfo file = new FileInfo(filename);

int length = (int)file.Length;

char[] source = new char[length];

using (TextReader reader = file.OpenText())

{

reader.Read(source, 0, length);

}

return source;

}

Reader将会被恰当的关闭。简单说来,using语句有大量的特征能够改善开始的“理想”版本。首先,我们看一下它内在的运行机制到底是怎样的。

using语句转换

C#ECMA标准描述using声明:

using (type variable = initialization)

embeddedStatement

它等同于

{

type variable = initialization;

try

{

embeddedStatement

}

finally

{

if (variable != null)

{

((IDisposable)variable).Dispose();

}

}

}

它依赖于System命名空间中的IDisposable接口:

namespace System

{

public interface IDisposable

{

void Dispose();

}

}

注意:finally程序块中的牵制转换意味着,这个变量必须是一个支持IDisposable接口的类(通过继承或转换操作)。如果它不是,你就会得到一个编译时错误。

using TextReader 转换

不出乎意料,TextReader支持IDisposable接口,并且实现了Dispose来调用关闭。这意味着:

using (TextReader reader = file.OpenText())

{

reader.Read(source, 0, length);

}

相当于下面:

{

TextReader reader = file.OpenText();

try

{

reader.Read(source, 0, length);

}

finally

{

if (reader != null)

{

((IDisposable)reader).Dispose();

}

}

}

除了对IDisposable的强制转换外,这和最通用的Java解决方式是相同的。这个强制转换是必须的因为这是一个通用解决方式。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有  導航