我的方法应该抛出它自己的异常,还是在文件不存在时让.NET 抛出?

这是我的代码:

public void ReadSomeFile(string filePath)
{
if (!File.Exists(filePath))
throw new FileNotFoundException();


var stream = new FileStream(filePath, ....)
.....
}

我是否应该自己抛出异常(参见 File.Exists检查) ?如果文件不存在,FileStream将已经抛出 FileNotFoundException。什么是良好的编程实践?代码分析表明我们应该验证我们的参数。但是如果我将这个参数直接传递给另一个方法(我的或其他人的代码) ,而该方法将抛出异常本身,那么在我的代码中验证参数有什么好处呢?

5900 次浏览

if (File.Exists(f)) { DoSomething(f) } (or the negation thereof) is an anti-pattern. The file can be deleted or created in between those two statements, so it makes little sense to check its existence like that.

Apart from that, as pointed out in the comments, while File.Exists() may return true, the actual opening of the file can then still fail for a variety of reasons. So you'll have to repeat the error checking and throwing around the opening of the file.

As you don't want to repeat yourself but instead keep your code DRY, just attempt to open the file and let new FileStream() throw. Then you can catch the exception, and if you wish, re-throw the original or throw an application-specific exception.

Of course calling File.Exists() can be justified, but not in this pattern.

Your method is called ReadSomeFile and takes a filename as its input, therefore it is reasonable for it to throw a FileNotFoundException. As you cannot add any value by catching the exception then throwing it yourself, just let .NET throw it.

However if your method was LoadData(databaseName) and it has to access many files, catching the exception, and throwing a custom exception may be of value, as you could add the databaseName to the exception along with other helpful information.

Aside from the already-given answers, you could also say that this depends on what you expect to happen.

If you want to read a log file and it does not exist, do you want to throw an error, or just an empty String (or empty String array)?

If returning a default value (like an empty String) I would simply wrap the content of the function in a try-catch (but only for expected errors) and return the default in the catch block, while returning the actual content in the try block.

This would leave three possible situations:

  1. The content of a file is returned;
  2. The default value is returned, because an expected error occurred;
  3. An error is thrown by .NET, because you did not catch that specific error.

Let the correct method try to open the file while you don't have any idea about full file name, somethings like special file names (eg. Device files and UNC paths):

In some cases other file methods may be failed, but opening the file is successful.

Some examples for special file names are:

  • CON
  • NUL
  • COM1, COM2, COM3, COM4
  • \\server\share\file_path
  • \\teela\admin$\system32 (to reach C:\WINNT\system32)
  • C:..\File.txt
  • \\.\COM1
  • %TEMP%
  • and more...