0

我最近才开始研究例外情况和使用它们的最佳实践,我想知道这样做的正确方法是什么:

假设有一个具有多个参数的方法。该方法有多个参数较少的重载,通过提供默认值来调用主实现。

我是否验证每个重载中的所有参数?

public string Translate(string text)
{
    if (String.IsNullOrEmpty(text))
        throw new ArgumentNullException();

    return Translate(text, "english");
}

public string Translate(string text, string language)
{
    if (String.IsNullOrEmpty(text))
        throw new ArgumentNullException();

    // Do the rest of the work
    // ...
}

我是否重新抛出异常?

public string Translate(string text)
{
    try
    {
        return Translate(text, "english");
    }
    catch
    {
        throw;
    }
}

public string Translate(string text, string language)
{
    if (String.IsNullOrEmpty(text))
        throw new ArgumentNullException();

    // Do the rest of the work
    // ...
}

还是我完全放弃异常并在重载中尝试/捕获块?

public string Translate(string text)
{
    return Translate(text, "english");
}

public string Translate(string text, string language)
{
    if (String.IsNullOrEmpty(text))
        throw new ArgumentNullException();

    // Do the rest of the work
    // ...
}

另外,这两种方法的文档会是什么样子?

(使用 C# XML 注释。尤其是我放置<exception>元素的地方。)


我确实意识到这是一个小话题,但是,每次遇到这种情况(实际上经常发生)时,我都会一直想知道。

4

4 回答 4

3

可选参数以某种方式解决了这个问题,那么你只有一个方法:

public string Translate(string text, string language="english")

有一些关于可选参数的怪癖很值得了解。

默认值被“烘焙”到调用代码中。[...] 这可能导致的问题与公开公共常量相同 - 如果您更改库中的默认值,但不重新编译调用代码,那么调用代码仍将调用您的方法旧的默认值。这绝对是您在使用可选参数设计 API 时需要考虑的问题。

于 2012-09-30T00:25:38.237 回答
2

让我们列出您拥有并决定的三个选项的优缺点:

1. 我是否验证每个重载中的所有参数?

优点:你会知道字符串是否为空,然后抛出异常。经典又好。缺点:您在抛出异常后调用第二个函数,知道由于字符串为空或 null 而发生异常。

所以我会放弃这个想法。

2. 我是否重新抛出异常?

优点: 1)这是我个人最喜欢的,好像你一行一行地发生这种情况。第二个函数被调用,异常被抛出并被调用函数的 catch 捕获,其他一些工作也完成了。2)使用 throw 关键字而不是 throw ex 确保您的堆栈跟踪是完整的。3)在调用部分处理异常是最佳实践。

缺点:请帮助我解决缺点。我没有找到。

3. 或者我是否完全丢弃异常并在重载中尝试/捕获块?

优点:调用函数中未使用 Try catch。不完全是专业人士,但是嗯,它减少了一些代码。缺点:不存在适当的处理,最佳实践表明我们应该在调用函数处处理异常。

我认为第二种选择是最好的选择。

还有一个我想分享的链接,这真的很有帮助

最佳实践:代码项目链接

请告诉我。

于 2012-09-30T00:57:19.917 回答
0

实际上,这是一个传统问题,在加密中被认为最好用所谓的静态工厂方法 - 通常命名getInstance()- 你将很多问题重构到一个地方。试图通过所有你得到的响应而变得相当讨厌,但永远不会因为什么都不做而抛出异常,只是大大简化了最终用例,要么将某些内容保存在日志中并快速失败,要么确保你在学生环境。

于 2012-09-30T00:23:17.853 回答
0

我在这里回答迟了,但我想指出,如果你正确地进行重载,这真的不应该是一个问题。重载到的正确方法是将所有功能代码放在接受所有可能参数的方法中:

public string Foo(string param1, string param2, string param3)
{
    // do work here, including throwing argument exceptions
}

然后,您的重载应该使用默认值填充缺失的参数:

public string Foo(string param1)
{
    return Foo(param1, null, null);
}

public string Foo(string param1, string param2)
{
    return Foo(param1, param2, null);
}

基于此,您只需要处理主要重载中的异常(实际执行任务的异常)。请记住,您的重载本身不应导致引发异常。例如,如果param3通过 throwing 强制不为 null ArgumentNullException,那么您不应该传递null该参数,而应该传递一些可以作为默认值的实际字符串。

无论最终调用哪个重载,都会调用主重载(带有 throws),并且它抛出的任何异常都会冒泡到原始代码。换句话说,您不需要执行以下操作:

public string Foo(string param1)
{
    if (param1 == null)
    {
        throw new ArgumentNullException(nameof(param1));
    }

    return Foo(param1, "param2 default", "param3 default");
}

因为主重载已经进行了该检查,并且如果param1为 null 则会抛出异常。

于 2017-08-18T17:03:14.350 回答