Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns &引用;TryParse/Parse-like;模式:实现它的最佳方式是什么_Design Patterns_Return Value_Try Catch - Fatal编程技术网

Design patterns &引用;TryParse/Parse-like;模式:实现它的最佳方式是什么

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

这个问题是我的后续问题。xxx()Tryxxx()模式在许多库中都非常有用。我想知道在不重复代码的情况下提供这两种实现的最佳方式是什么

什么是最好的:

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");
    }
}