我有一个方法Foo()做了一些努力工作,在UI层我有一个按钮来调用该方法。
我想要做的就是调用方法并在Foo()方法出现问题时显示消息框。
我有两种选择来设计方法签名:
1.Tuple
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.Exception
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.
您更喜欢哪一个,为什么?
答案 0 :(得分:3)
抛出异常并以一致的方式处理它会更好。
如果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);
}
}
答案 1 :(得分:1)
这实际上取决于你的需要。像这样修改你的代码,它也会处理未处理的异常。
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");
}
}
答案 2 :(得分:1)
如果您正在做的就是调用这些外部方法来完成一些工作,而您正在编写的这个方法是它们的包装,那么为什么抛出异常,“处理”方法中的问题并继续,抛出和处理例外很多很多次更贵
在你的特定情况下,你所做的只是做一些工作,并显示一个消息框来显示它是否正确执行,所以我选择了1
请注意,如果您只是捕获异常而不是展开堆栈,则成本相当低。当您展开堆栈时,它只是昂贵的,例如ex.ToString()
或ex.StackTrace
答案 3 :(得分:0)
我做过的一次是成功时返回null或失败时返回错误消息。异常是不合适的,因为失败是可能的,而其他开发人员喜欢运行“在抛出异常时中断”
String Foo()
{
if(!DoHardWorkA()) return "cannot do hardwork A";
if(!DoHardWorkB()) return "cannot do hardwork B";
return null;
}
答案 4 :(得分:0)
使用异常有一个建议,即您可以(*)比建议的元组返回值更容易区分原因。要弄清楚在使用元组时出现什么样的错误,你必须解释字符串值,这很容易出错。使用异常,您可以根据异常的类型确定错误类型。
(*)取决于如何使用异常 - 如果你一直抛出一般的异常,它将不会有所不同
当然你可以在元组中使用一个整数来表示问题的类型,但是错误类型的数值不像Exception类型那样具有描述性(再次假设你没有使用一般类型,比如除外)。