C#:递归调用中的异常处理

Ste*_*ger 6 c# recursion exception-handling

我有一个递归方法调用.当抛出任何异常时,我想看看,在递归调用堆栈中它发生了什么.我有一个字段,其中包含一个代表递归堆栈的"路径".

现在我想将路径信息添加到可能在递归调用中抛出的任何异常.

void Recursive(int x)
{
  // maintain the recursion path information
  path.Push(x);

  try
  {
    // do some stuff and recursively call the method
    Recursive(x + 6);
  }
  catch(Exception ex)
  {
    if (ex is RecursionException)
    {
      // The exception is already wrapped
      throw;
    }
    // wrap the exception, this should be done only once.
    // save the path and original exception to the wrapper.
    throw new RecursionException(path.ToString(), ex);
  }
  finally
  {
    // maintain the recursion path information
    path.Pop()
  }
}
Run Code Online (Sandbox Code Playgroud)

它看起来太复杂了.不仅有一种方法.可能有二十个甚至更多的地方我必须编写这段代码.

有没有更简单的方法来实现这个?


编辑:要指出这一点:我想有一个更简单的情况,没有这样的开销递归调用方法,因为我有很多这样的递归调用,不仅有一个方法,还有几个方法递归地互相呼叫,这很复杂.

所以我想避免整个try-catch块,但我看不出任何解决方案.

对于我自己的代码中抛出的异常,这不是一个大问题,因为它可能包含从头开始的路径.但这是每个其他例外的问题.


编辑:异常需要包装在任何其他代码中,而不仅仅是在调用递归方法时:

  try
  {
    int a = 78 / x; // DivisionByZeroExeption        

    Recursive(x + 6);

    this.NullReference.Add(x); // NullReferenceException
  }
Run Code Online (Sandbox Code Playgroud)

因此只包含对Recusive的调用不起作用.

有很多这样的方法,有不同的签名,做不同的事情,唯一常见的是异常处理.

Dav*_*wns 5

只是简化(略微)异常处理:

void Recursive(int x)
{
    // maintain the recursion path information
    path.Push(x);

    try
    {
        // do some stuff and recursively call the method
        Recursive(x + 6);
    }
    catch( RecursionException )
    {
        throw;
    }
    catch( Exception )
    {
        throw new RecursionException(path.ToString(), ex);
    }
    finally
    {
        // maintain the recursion path information
        path.Pop()
    }
}
Run Code Online (Sandbox Code Playgroud)

如果对你有任何用处,你会收到带有异常的callstack信息,除此之外你可以把它写成一个片段,然后只需将它插入你需要重新使用的地方.

还有以下可能性,这将是缓慢但应该工作:

void DoStuff()
{
    this.Recursive(1, this.RecursiveFunction1);
    this.Recursive(2, this.RecursiveFunction2);
}

bool RecursiveFunction1(int x)
{
    bool continueRecursing = false;

    // do some stuff
    return continueRecursing;
}

bool RecursiveFunction2(int y)
{
    bool continueRecursing = false;

    // do some other stuff here
    return continueRecursing;
}

private void Recursive(int x, Func<int, bool> actionPerformer)
{
    // maintain the recursion path information
    path.Push(x);

    try
    {
        // recursively call the method
        if( actionPerformer(x) )
        {
            Recursive(x + 6, actionPerformer);
        }
    }
    catch( RecursionException )
    {
        throw;
    }
    catch( Exception ex )
    {
        throw new RecursionException(path.ToString(), ex);
    }
    finally
    {
        // maintain the recursion path information
        path.Pop();
    }
}
Run Code Online (Sandbox Code Playgroud)


Ian*_*ose 3

我认为您正在尝试在异常详细信息中包含递归路径以帮助调试。

\n\n

尝试一下这个怎么样?

\n\n
public void Recursive(int x)\n{\n  try\n  {\n    _Recursive(x)\n  }\n  catch\n  { \n    throw new RecursionException(path.ToString(), ex);\n    clear path, we know we are at the top at this point\n  }\n}\n\nprivate void _Recursive(int x)\n{\n    // maintain the recursion path information\n    path.Push(x);\n\n    _Recursive(x + 6);\n\n    //maintain the recursion path information\n    //note this is not in a catch so will not be called if there is an exception\n    path.Pop()\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您正在使用线程等,您可能必须查看线程本地存储中的存储路径。

\n\n
\n\n

如果您不希望强制调用者处理 RecursionException,则可以将 \xe2\x80\x9cpath\xe2\x80\x9d 公开,以便调用者可以访问它。(正如埃里克·利珀特后来的回答)

\n\n

或者,您可以在捕获异常时记录错误日志系统的路径,然后重新抛出异常。

\n\n
public void Recursive(int x)\n{\n  try\n  {\n    _Recursive(x)\n  }\n  catch\n  { \n    //Log the path to your loggin sysem of choose\n    //Maybe log the exception if you are not logging at the top \n    //   of your applicatoin         \n    //Clear path, we know we are at the top at this point\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样做的优点是调用者根本不需要知道 \xe2\x80\x9cpath\xe2\x80\x9d。

\n\n

这一切都取决于您的调用者的需求,不知何故,我认为您是此代码的调用者,因此我们没有必要尝试第二次猜测此级别的交易需要什么。

\n