Design patterns &引用;TryParse/Parse-like;模式:实现它的最佳方式是什么
这个问题是我的后续问题。xxx()Tryxxx()模式在许多库中都非常有用。我想知道在不重复代码的情况下提供这两种实现的最佳方式是什么 什么是最好的:Design patterns &引用;TryParse/Parse-like;模式:实现它的最佳方式是什么,design-patterns,return-value,try-catch,Design Patterns,Return Value,Try Catch,这个问题是我的后续问题。xxx()Tryxxx()模式在许多库中都非常有用。我想知道在不重复代码的情况下提供这两种实现的最佳方式是什么 什么是最好的: public int DoSomething(string a) { // might throw an exception } public bool TrySomething(string a, out result) { try { result = DoSomething(a) r
public int DoSomething(string a)
{
// might throw an exception
}
public bool TrySomething(string a, out result)
{
try
{
result = DoSomething(a)
return true;
}
catch (Exception)
{
return false;
}
或
我本能地认为第一个示例更正确(您确切地知道发生了哪种异常),但是try/catch是否太贵了?在第二个示例中,是否有捕获异常的方法?如果您只是捕获异常,而不执行任何操作,只返回false,那么第一个示例是正确的 您可以将TrySomething更改为如下所示
public bool TrySomething(string a, out result, bool throwException)
{
try
{
// Whatever
}
catch
{
if(throwException)
{
throw;
}
else
{
return false;
}
}
}
public bool TrySomething(string a, out result)
{
return TrySomething(a, out result, false);
}
所以有什么东西看起来像
public int DoSomething(string a)
{
int result;
// This will throw the execption or
// change to false to not, or don't use the overloaded one.
TrySomething(a, out result, true)
return result;
}
如果你不想尝试将ThroweException公开,你可以让它成为私人会员
异常可能会很昂贵,您可以对字符串进行一些正则表达式检查,以防止抛出异常。这取决于你想做什么。假设这是C,我会说第二个例子
public bool TrySomething(string a, out result)
{
try
{
result = DoSomething(a)
return true;
}
catch (Exception)
{
return false;
}
}
它模仿内置的
int.TryParse(字符串s,out int result)
,我认为最好与语言/环境保持一致。我通常使用这种模式。取决于内部方法的实现方式,这是否有意义。如果你不得不使用条件捕获块,它可能会变得有点糟糕
public object DoSomething(object input){
return DoSomethingInternal(input, true);
}
public bool TryDoSomething(object input, out object result){
result = DoSomethingInternal(input, false);
return result != null;
}
private object DoSomethingInternal(object input, bool throwOnError){
/* do your work here; only throw if you cannot proceed and throwOnError is true */
}
让尝试只是抓住并吞下例外是一个非常糟糕的主意。TryXXX模式的一半要点是避免异常对性能的影响 如果在异常中不需要太多信息,可以让DoSomething方法只调用TrySomething并在失败时抛出异常。如果您需要异常中的详细信息,您可能需要更详细的信息。我还没有对异常的大部分性能影响进行计时-如果是抛出而不是创建,您可以编写一个私有方法,该方法具有与TrySomething类似的签名,但返回异常或null:
public int DoSomething(string input)
{
int ret;
Exception exception = DoSomethingImpl(input, out ret);
if (exception != null)
{
// Note that you'll lose stack trace accuracy here
throw exception;
}
return ret;
}
public bool TrySomething(string input, out int ret)
{
Exception exception = DoSomethingImpl(input, out ret);
return exception == null;
}
private Exception DoSomethingImpl(string input, out int ret)
{
ret = 0;
if (input != "bad")
{
ret = 5;
return null;
}
else
{
return new ArgumentException("Some details");
}
}
不过,在你做出承诺之前,一定要花点时间 我同意你的直觉(如果可能的话,避免TryX的异常),只要你的TryX实现不需要捕获异常(即,异常是由你的代码生成的,而不是你调用的代码)。此外,我不确定你所说的“第二个例子中有没有捕获异常的方法?”--抓住什么例外?你想从DoSomething抛出异常(尽管你会抛出一个特定于所发生的异常,而不是一般的异常)。@Jonathan:我的意思是“以调用方可以知道错误原因的方式重新抛出内部处理中发生的异常”,我不会将带有“throweexception”arg的版本作为公共版本;这已经隐含在你选择称之为“尝试”或“某事”的过程中。不过,作为一个位于两个公共实现后面的私有方法,这可能还可以。在公共方法上使用bool throwException这样的参数并不好——请参见.NET Framework设计指南。此外,吞下异常也不好:)是的,但这意味着如果throwOnError为false,DoSomethingInternal决不能抛出异常,这可能会导致实现成本高昂,不是吗?正如我所说,这可能会很糟糕,这取决于内部方法的实现。换句话说,如果您不在调用堆栈的底部,并且您调用了可能引发异常的方法,那么它可能不是最佳模式。但是,大多数情况下,您会发现,您可以避免引发使用此处其他示例可能引发的异常,这样可以节省一些堆栈展开时间。这与接口一致,但不是为了避免异常对性能的影响。它也错误地(IMO)吞并了所有异常,而不仅仅是DoSomething通常会抛出的异常。例如,我不希望OutOfMemoryException被吞没。我喜欢这个实现,我可能会在可能的时候进一步测试它
public int DoSomething(string input)
{
int ret;
Exception exception = DoSomethingImpl(input, out ret);
if (exception != null)
{
// Note that you'll lose stack trace accuracy here
throw exception;
}
return ret;
}
public bool TrySomething(string input, out int ret)
{
Exception exception = DoSomethingImpl(input, out ret);
return exception == null;
}
private Exception DoSomethingImpl(string input, out int ret)
{
ret = 0;
if (input != "bad")
{
ret = 5;
return null;
}
else
{
return new ArgumentException("Some details");
}
}