3

在 System.IO 中有一个函数:string File.ReadAllText(string path);

我正在尝试编写一个调用 File.ReadAllText 的函数,处理所有可能的异常并返回 true/false 并存储错误消息。

我所拥有的是:

public static class FileNoBS
{
    public static bool ReadAllText( string path, out string text, out string errorMessage )
    {
        errorMessage = null;
        text = null;
        bool operationSuccessful = false;

        try
        {
            text = System.IO.File.ReadAllText( path );
            operationSuccessful = true;
        }
        catch ( ArgumentNullException e )
        {
            errorMessage = "Internal software error - argument null exception in FileNoBs.ReadAllText\nMessage: " + e.Message;
        }
        catch ( ArgumentException e )
        {
            errorMessage = "Internal software error - path is a zero-length string, contains only white space, or contains one or more invalid characters as defined by InvalidPathChars in FileNoBs.ReadAllText.\nMessage: " + e.Message;
        }
        catch ( PathTooLongException e )
        {
            errorMessage = "The specified path was too long.\nMessage: " + e.Message;
        }
        catch ( DirectoryNotFoundException e )
        {
            errorMessage = "The specified directory was not found.\nMessage: " + e.Message;
        }
        catch ( FileNotFoundException e )
        {
            errorMessage = "The file specified in path was not found.\nMessage: " + e.Message;
        }
        catch ( IOException e )
        {
            errorMessage = "An I/O error occurred while opening the file.\nMessage: " + e.Message;
        }
        catch ( UnauthorizedAccessException e )
        {
            errorMessage = @"UnauthorizedAccessException

path specified a file that is read-only.
-or-
This operation is not supported on the current platform.
-or-
path specified a directory.
-or-
The caller does not have the required permission.\nMessage: " + e.Message;
        }
        catch ( NotSupportedException e )
        {
            errorMessage = "path is in an invalid format.\nMessage: " + e.Message;
        }
        catch ( SecurityException e )
        {
            errorMessage = "You do not have the required permission.\nMessage: " + e.Message;
        }

        return operationSuccessful;
    }
}

我不明白控制流如何与返回值的函数一起使用。假设 UnauthorizedAccessException 被捕获,errorMessage 设置为

    errorMessage = "You do not have the required permission..."

我知道 finally 每次都会执行,但是编译器不会让我在 finally 块中返回。那么我的回报是否会达到?

另一个问题是如何在遵循官方指南的同时简化这一过程:“一般来说,你应该只捕获那些你知道如何从中恢复的异常。”

我害怕从 File 类(Move、Copy、Delete、ReadAllText、WriteAllText)和 Directory 类中遍历我需要的所有函数,并执行所有这些长代码块只是为了捕获所有我不关心和不捕获的异常太多了,因为微软说它很糟糕。

谢谢你。

编辑:我得到这样的评论不是处理异常这是“别的东西”。

我是我的代码的客户,我想做这样的事情:

if ( !FileNoBS.ReadAllText( path, text, errorMessage ) ) {
   MessageBox.Show( errorMessage );
   return;
}
// continue working with all errors taken care of - don't care for whatever reason file wasn't opened and read, user is notified and I am moving on with my life
4

6 回答 6

4

由于 try 块或 catch 块中没有返回,因此将达到您的返回。

通常,您只想捕获您期望可能发生的异常并有办法处理它们。例如,您可能希望处理从给定路径中找不到的文件,并改为返回默认文件。您应该允许不捕获其他异常,以便您知道发生了意外的事情,而不是通过捕获所有异常来隐藏它。

于 2013-05-27T05:44:11.407 回答
2

正如我在评论中所说,您最好在更高级别处理异常并简单地显示异常消息,而不是手动设置每条消息。我认为在这种情况下,来自异常的消息将具有足够的描述性。

    public static class FileNoBS
    {
        public static string ReadAllText(string path)
        {
            return System.IO.File.ReadAllText( path );
        }   
    }

然后在您的应用程序的更高级别上使用它。我通常有一个通用处理程序来处理所有应用程序异常并记录它们并在必要时显示一个消息框。

    try
    {
        var text = FileNoBS.ReadAllText("file.ext");
    }
    catch(Exception e)
    {
    Console.WriteLine(e.Message);
    }
于 2013-05-27T06:02:40.513 回答
1

而不是捕获异常,您应该尽量避免首先引发这些异常的情况。在您的情况下,您应该在调用之前进行一些输入验证ReadAllText

  • 永远不要接受为空的路径 - 你知道这会导致异常,所以在它发生之前处理它
  • 从不接受导致文件不存在的路径 -File.Exists(path)在调用之前使用
  • 从不接受格式错误的路径,例如空字符串或包含无效字符的路径 - 这将导致异常

这些测试应在输入的来源处执行。也就是说,如果用户输入它们,请在使用它们之前验证它们。如果它们来自数据库或其他地方,请在使用前验证那里。如果不是用户输入,它们都是系统错误的迹象,应该被视为这样,而不是用户应该担心的事情。

安全异常可能更难预先测试,并且在许多情况下,出现违规是异常的,因此完全可以得到异常。它当然不应该使程序崩溃,而是通过向用户发送错误消息来处理(如果它基于用户输入,如果是系统生成的数据导致了这种情况,则表明系统错误应该在代码级别修复)。在调用发生的地方执行此操作通常比在某些库方法中更合适。

因为IOExceptions它们可以放入两个桶中。可恢复一次(通常是重试)和不可恢复一次。作为最低要求,向用户提供有关异常的反馈,以便用户可以选择重试。

一个非常普遍的规则应该是纠错逻辑的一部分,那就是永远不要让无效数据在系统中浮动。确保所有对象都管理不变量(为此提供了工具,例如代码合同)。当收到来自用户(或其他系统)的无效输入而不是在它们导致异常时拒绝它们。

如果您完成了所有输入验证并且仍然有 Eg ArgumentNullException,那么这表明程序逻辑中存在错误,您希望能够在测试中轻松找到并在发布错误之前进行更正。你不应该试图掩盖这个错误。

于 2013-05-27T06:45:42.493 回答
0

return 语句将在代码中出现任何异常的情况下被调用,然后在程序退出之前将其放置在程序的末尾。

我建议放置一个具有高级异常类型的异常处理程序,例如“异常”类型本身,并打印或记录异常消息。在每个方法中指定如此多的异常处理程序将花费大量精力,您实际上应该将这些精力投入到方法本身中。

        try
        {
            return ReadAllText("path", "text", "error");
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
        }
        return false;

因此,如果该方法被调用,它将立即返回,否则将打印/记录异常并且该方法将返回 false。

但是,在某些情况下,您可以提及几个或几个显式异常处理程序,您认为这将是有益的。

于 2013-05-27T06:58:20.073 回答
0

如果没有发生其他错误,是的。

我会在最后添加:

catch (Exception e)
{
    errormessage = "An unexpected error has occured.";
}

return operationSuccessful;

但是,即使您遇到错误,这也将始终返回成功。我不确定这是否是您想要的,或者您的变量是否命名错误。

于 2013-05-27T05:48:48.117 回答
-2

是的,它将返回该值。

但是,最好return在 finally 语句中处理值。

如果在任何情况下都想返回 operationSuccessful 值,那么在 catch 块之后编写 finally 块,如下所示,

finally
{
  return operationSuccessful;
}
于 2013-05-27T05:45:19.283 回答