事实上,我尝试了我的代码防错,最终使它看起来相当混乱。
我设置了一个函数来读取某种类型的文件。如果有问题,我希望函数返回false,如果一切正常,则返回true。我不知道如何组织这些东西。
我有一个初始的try-catch块,它试图打开文件流。在此之后,我在读取过程中进行了一些其他检查,例如文件大小和特定偏移量的值。我设置它的方式是用if else语句。如:
if(condition){
}
else{
MessageBox.Show("There was an error");
br.Dispose();
fs.Dispose();
return false;
}
…Br是二进制读取器,fs是文件流。这样的代码块有很多,多次编写相同的代码似乎是不好的做法。首先想到的是用try-catch语句包装整个代码并抛出异常,而不是使用if else语句块。我记得在阅读try-catch语句时,有它们是好的,但不要用它们包住所有内容。老实说,我仍然不完全理解为什么把所有东西都包装在try catch语句中是不好的做法,因为它们只在出现错误时起作用,在这种情况下,程序无论如何都会出错……
另外,我是否必须关闭二进制读取器和文件流,或者关闭一个会关闭另一个?有没有一种不用处理就能使用它们的方法?
如何使用using
关键字?这将在try - finally块中封装IDisposable
;
bool success = true;
using(var fs = new FileStream(fileName, FileMode.Create)))
using(var br = new BinaryReader(fs))
{
// do something
success = result;
}
return success;
嵌套的using块将确保文件流和二进制读取器总是被正确关闭和处置。
您可以阅读更多关于在MSDN中使用的信息。它使IDisposable
的使用更加简洁,消除了显式异常处理的需要。
关于你的声明:
我记得当我读到try-catch语句的时候,它是好的拥有它们,但不要把所有的东西都用它们包起来。
我总是使用一个简单的规则:如果我不能处理和恢复特定代码块中的异常,就不要试图捕获它。允许异常在堆栈中"冒泡"到捕获它更有意义的点。使用这种方法,您将发现不需要添加许多try-catch块,您将倾向于在与服务(如文件系统、网络等)集成时使用它们,但您的业务逻辑几乎总是没有异常处理机制。
只需为您的一次性对象使用using
关键字。在using
关键字的块内,您可以throw
异常或return
,而不必担心处理;它会自动为你发生。
try-catch
块不是一个很好的主意,只是因为存在一个更好的选择:try-finally
块。但是using
关键字甚至更好,因为它本质上扩展成一个try-finally
块,它负责对象的处理。
关闭文件流也会关闭二进制读取器,处理它们也会关闭。你为什么要使用它们而不处理它们?处理它们更好,通过using
处理它们是最好的方法。
我认为确保文件流被处理的最好方法是将它们的使用与以下using
块包装在一起
using (FileStream)
{
....
}
是的,这是不好的做法。
应该抛出异常,而不是返回指示问题是否发生的布尔值。例子:
if (headNotValid)
throw new Exception("Header was not valid");
在某些情况下,创建一个新的异常类可能是明智的。
当处理从IDisposable
继承的类时,你应该使用using
指令。
using (var stream = new FileStream(filename))
{
}
保证你的流被处理,即使在using
块中抛出异常。
总之,我更喜欢这样:
private void string ParseFile(string filename)
{
using (var stream = new FileStream(filename))
{
if (somethingNotValid)
throw new Exception(...);
return ...;
}
}
And in your main:
{
try
{
var value = ParseFile(filename);
}
catch (Exception)
{
Console.WriteLine(..);
}
}
使用using
关键字。使用using
,您可以这样重写:
public static int CountCars()
{
SqlConnection conn = new SqlConnection(connectionString);
try
{
SqlCommand cmd = conn.CreateCommand();
conn.Open();
try
{
cmd.CommandText = "SELECT COUNT(1) FROM Carsd";
return (int)cmd.ExecuteScalar();
}
finally
{
if(cmd != null)
cmd.Dispose();
}
}
finally
{
if(cmd != null)
conn.Dispose();
}
}
这:
public static int CountCars()
{
using(SqlConnection conn = new SqlConnection(connectionString))
using(SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT COUNT(1) FROM Carsd";
return (int)cmd.ExecuteScalar();
}
}
两个代码片段在编译时将产生完全相同的IL代码。这些例子来自http://coding.abel.nu/2011/12/idisposable-and-using-in-c/,我在那里写了更多关于使用和IDisposable
的细节。