如何知道某些方法是否可以抛出异常

时间:2013-08-19 14:38:50

标签: c# windows-8 windows-runtime

我是Windows 8和C#开发的新手,但我对Java编程有一定的经验。

所以,当我尝试在java中创建一些Json解析器(例如)时,我不能在不使用try-catch块的情况下执行此操作,这样我就可以处理异常,但是当我尝试执行同样在c#(Windows 8)中,我也不使用try-catch块,它也可以,如下所示:

if (json != null)
{
        JObject jObject = JObject.Parse(json);

        JArray jArrayUsers = (JArray)jObject["users"];

        foreach (JObject obj in jArrayUsers)
        {
            ListViewMainViewModel user = new ListViewMainViewModel(
                (String)obj["email"],
                (String)obj["token"],
                (String)obj["institution"],
                (String)obj["uuidInstitution"]);

            usersList.Add(user);
        }
        return usersList;
    }

}

我知道正确的方法是捕获JsonReaderException,但Visual Studio从未警告过我。我想知道是否有一种简单的方法可以知道某个方法是否会抛出异常,就像在使用eclipse的java上一样(它是强制实现try-catch块或代码不会编译)

4 个答案:

答案 0 :(得分:25)

您必须查阅相关文档。 C#缺少throws关键字。

您要查找的内容是已检查的例外,可以在C# FAQ中找到更多信息。

答案 1 :(得分:16)

在C#中,你负责处理异常 - 恕我直言,这是比Java实现更好的方式。实际上,异常应该是例外,即:这不是你应该总是期望发生的事情

考虑这种反对模式(但是,常见的)反模式:

try {


} catch (Exception ex) { /* Handler goes here */ }

究竟是什么意思?你真的要处理通过这里的每一个例外吗?甚至像OutOfMemoryException这样的东西?那太疯狂了。这种模式将导致的唯一问题是抑制真正应该关闭应用程序的合法异常 - 这与Java方法非常相似。

Exception视为程序员的标志,说'嘿,环境刚刚进入一个不可能的状态'。例如,如果我尝试除以零并且系统抛出DivideByZeroException,那么系统应该正确地提醒您,因为这是一个失败 - 一个系统不能只是'想象它的出路' - 如果你只是压制这个问题,那真的有什么帮助?最后这会适得其反,因为你正在做的就是掩盖真正不可能的应用程序状态。如果你在你的应用程序中做了很多这样的事情,那么它最终会变成有毒错误的污泥。呸!

例外也占用了大量的屏幕空间。有时我希望他们能让try/catch/finally块更精简,但我记得这样做会鼓励人们更多地使用它们,所以我很快就悔改了这个位置。

例外是有用的程序员到程序员通知,说你正在做的事情没有意义。显然,我们不应该将原始异常传递给用户,因为他们不知道如何处理它们。同时,你不想尝试处理地球上的每一个例外,因为在这种意义上的“处理”通常会转变为“抑制”,这比让应用程序失败更加糟糕(优雅地) )。

答案 2 :(得分:15)

如上所述,C#没有检查异常,谢天谢地。

检查异常的想法听起来很棒,但是与任何被迫通过语言或运行时使用它们的人交谈,并且他们会说有三个检查异常的大问题:

  • 他们将自己的意志强加于消费者编码器。根据他们的定义,检查的异常应该在它们被抛出运行时之前被处理。运行时实际上告诉编码器"当我抛出它时你应该知道该怎么做,所以这样做"。首先,考虑一下;根据其定义,您被告知期望 例外案件中发生的事情。其次,你预计会以某种方式处理它。好吧,当你真正有能力解决异常所指出的问题时,这一切都很好。不幸的是,我们并不总是拥有这种能力,也不总是想做我们应该做的一切。如果我正在编写一个执行数据转换的简单表单小程序,而我只是希望我的应用程序在遇到任何问题时死于火热的死亡,我就不能抓到任何东西;我必须上升所有可能抛出一些东西的方法的所有可能的调用堆栈并添加它可以抛出到throws子句(或者非常懒惰并且在我的代码库的每个方法上放置一个"抛出异常"子句) )。同样,如果我的应用程序构造为我无法抛出特定的异常,可能是因为我实现了一个超出我控制范围的界面,并没有将其指定为一个潜在的throwable,然后我唯一的选择是完全吞下它并将可能无效的结果返回给我的调用者,或者将异常包装在一个未经检查的throwable类型中,如RuntimeException并将其抛出(忽略整个已检查的异常机制,当然不推荐这样做。)
  • 他们违反了SOLID,尤其是开放原则。进行更改,为您的代码添加已检查的异常,如果您无法处理所述异常,则使用您的方法的所有用法必须处理它或将自己标记为抛出异常。重新抛出的用法必须由他们自己的调用者处理,或他们必须被标记为抛出相同的异常。通过在特定代码行中调用替代方法进行外观更改,您现在必须跟踪所有可能的调用堆栈并对正常工作的代码进行其他更改,只是为了告诉他们您的代码可能会抛出一个异常。
  • 他们根据定义创建漏洞抽象。一个使用"抛出"实际上,子句必须知道有关其依赖性的这些实现细节。然后,如果它不愿意或无法处理这些错误,则必须告知其自己的消费者这些错误。当该方法是接口实现的一部分时,问题更加复杂;为了让对象抛出它,接口必须将它指定为throwable,即使并非所有实现都抛出该异常。

    Java通过具有多级异常类层次结构来缓解这种情况;例如,所有与I / O相关的异常(应该是)IOExceptions,以及具有与IO相关的方法的接口可以指定可以抛出IOException,从而减轻了指定每个特定子IOException的责任。然而,这导致几乎与它解决的问题一样多;有几十个IOExceptions,可能有不同的原因和解决方案。因此,您必须询问在运行时捕获的每个IOException以获取其 true 类型(并且您很少或根本没有帮助识别可能被抛出的特定类型)以确定它是否'你可以自动处理的事情,以及如何处理。

编辑:还有一个大问题:

  • 他们认为try-catch是处理可能异常情况的唯一方法。让我们说你在C#中的C#拥有Java的另一个世界中样式检查异常。您希望您的方法打开并读取给定调用者传入其中的文件名的文件。就像一个好的小程序员一样,你首先使用File.Exists验证文件是否存在于一个保护子句中(它永远不会抛出异常;为了返回true,路径必须是有效的,在路径中指定的文件必须存在,并且执行用户帐户必须至少具有对文件夹和文件的读访问权限。如果File.Exists返回false,则您的方法只返回没有数据,并且您的调用者知道该怎么做(比如这个方法打开一个包含可选配置数据的文件,如果它不存在,是空白或已损坏,程序生成并使用默认配置)。

    如果文件存在,则调用File.Open。好吧,File.Open可以抛出九种不同类型的异常。但是它们都不可能发生,因为您已经使用File.Exists验证了该文件可以由运行该程序的用户以只读方式打开。然而,检查过的异常机制并不关心;您正在使用的方法指定它可以抛出这些异常,因此您必须处理它们或指定您自己的方法可以抛出它们,即使您可能采取一切预防措施来阻止它。首选答案是吞下它们并返回null(或忘记保护条款,只是捕获并处理File.Open的例外),但那是你试图避免使用的模式。保护条款首先。

这甚至都没有考虑到邪恶的可能性。例如,开发人员可能会捕获并将未经检查的异常封装为已检查的异常(例如,捕获NullPointerException并抛出IOException),现在您必须捕获(或指定您的方法抛出)异常,而不是#39甚至可以很好地代表什么是错误的。

至于在C#中使用的内容,最佳做法是使用XML documentation comments使用您的方法通知直接调用方可能会从中抛出异常。 XML-doc是与JavaDoc注释等效的.NET,并且以相同的方式使用,但语法不同(三个正斜杠后跟由XML标记系统包围的注释)。 tag for an exception很容易指定。为了有效地记录您的代码库,我建议GhostDoc。它只会为正在记录的方法中明确抛出的异常生成异常注释,但是,您必须填写一些空白。

答案 3 :(得分:-1)

我不是一个java开发人员,但从这里的答案来看,似乎Java实现对这些方法的客户来说是一种负担。但是,C#错过了一个机会(类似Java或其他方式)与调用者通信可能发生的异常结果的类型,由方法的开发人员编写,允许我调用者适当地处理它。

由于这个构造没有内置到语言中,我建议库开发人员采用包装类并将其用作任何可能出错的方法的返回类型。使用所述类作为返回类型代替异常,客户端可以推断在调用方法时会发生什么,因为它在方法签名中明确定义。此外,使用包装器将允许一种方法告诉客户端为什么出现问题的方式不会像异常一样破坏流程。

此处有关此主题的更多信息:http://enterprisecraftsmanship.com/2015/03/20/functional-c-handling-failures-input-errors/