返回元组<;bool,字符串>;而不是抛出exception()

本文关键字:exception gt lt 元组 bool 返回 字符串 | 更新日期: 2023-09-27 18:28:46

我有一个方法Foo()做一些艰苦的工作,在UI层上我有一个子按钮来调用该方法
如果Foo()方法有问题,我只想调用该方法并显示一个消息框。

我有两种选择来设计方法签名:

1.元组

Tuple<bool, string> Foo()  
{  
    if(!DoHardWorkA()) return Tuple.New(false, "cannot do hardwork A");  
    if(!DoHardWorkB()) return Tuple.New(false, "cannot do hardwork B");  
    return Tuple.New(true, String.Empty);
}

2.异常

void Foo()
{
    if(!DoHardWorkA()) throw new ProgramSpecificException("cannot do hardwork A");
    if(!DoHardWorkB()) throw new ProgramSpecificException("cannot do hardwork B");
    return Tuple.New(true, String.Empty);
}

DoHardWorkA()和DoHardWorkB()都是外部方法,我无法控制它们,它们返回true/false表示结果。

从逻辑上讲,我认为我应该选择选项2,因为它们确实是例外;但为了保持一致性,我想选择选项1。

你更喜欢哪一个,为什么?

返回元组<;bool,字符串>;而不是抛出exception()

抛出异常并以一致的方式进行处理会更好。

如果Foo由于任何其他原因失败,那么它也将被处理。假设一个场景。

void UIMethod()
{
   Tuple<Result, Error> ret = Foo();
   if(ret.Error)
     MessageBox.Show(ret.Error);
}

现在,由于需求的变化,您必须在Foo之前调用另一个方法,它也可能引发异常。然后它就变得复杂了。

这样做要容易得多。

void UIMethod()
{
   try{  
       MethodBeforeFoo();
       var ret = Foo();
    }
   catch(Exception ex)
    {
       MessageBox.Show(ex.Message); 
    }
}

这实际上取决于您的需要。像这样修改你的代码,它也会处理未处理的异常。

   Tuple<bool, string> Foo()  
{  
try
{
    if(!DoHardWorkA()) return Tuple.New(false, "cannot do hardwork A");  
    if(!DoHardWorkB()) return Tuple.New(false, "cannot do hardwork B");  
    return Tuple.New(true, String.Empty);
}
catch
{
  return Tuple.New(false, "cannot do hardwork A"); 
}

}

如果你所做的只是调用这些外部方法来完成一些工作,而你正在编写的这个方法是对它们的包装,那么为什么要抛出异常,"处理"方法中的问题并继续,抛出和处理异常会比贵很多很多

在您的特定情况下,您所做的只是做一些工作,并显示一个消息框来显示它是否正确执行,所以我选择选项1

请注意,如果您只是捕获异常而不展开堆栈,则成本相当小。只有当您展开堆栈时,它才是昂贵的,如ex.ToString()ex.StackTrace

使用异常具有优势,与建议的元组返回值相比,您可以更容易地(*)区分原因。要想弄清楚在使用元组时什么样的东西出错,必须解释字符串值,这很容易出错。使用异常,可以根据异常的类型确定错误的类型。

(*)取决于异常的使用方式——如果你一直抛出一个通用异常,那么就不会有什么不同

当然,您可以在元组中使用整数来指示问题的类型,但错误类型的数值不如异常类型具有描述性(再次假设您没有使用一般类型,如异常)。

我曾经做过的是在成功时返回null或在失败时返回错误消息。异常是不合适的,因为可能会失败,其他开发人员喜欢使用"抛出异常时中断"运行

String Foo()  
{  
    if(!DoHardWorkA()) return "cannot do hardwork A";
    if(!DoHardWorkB()) return "cannot do hardwork B";
    return null;
}