"TryParse/Parse like"模式:实现它的最佳方式是什么

Luk*_*Luk 9 design-patterns try-catch return-value

这个问题是如何表明方法不成功的后续问题.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;
    }
Run Code Online (Sandbox Code Playgroud)

要么

public int DoSomething(string a)
{
     int result;
     if (TrySomething(a, out result))
     {
         return result;
     }
     else
     {
         throw Exception(); // which exception?
     }
}
public bool TrySomething(string a, out result)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

我本能地假设第一个例子更正确(你确切知道发生了哪个异常),但是try/catch不能太昂贵吗?有没有办法在第二个例子中捕获异常?

Jon*_*eet 14

让TrySomething抓住并吞下异常是一个非常糟糕的主意.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");
    }
}
Run Code Online (Sandbox Code Playgroud)

在你承诺它之前计算时间!


小智 5

我通常使用这种模式。取决于内部方法的实现方式,这是否有意义。如果你必须使用条件 catch 块,它会变得有点讨厌......

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 */
}
Run Code Online (Sandbox Code Playgroud)