代码之家  ›  专栏  ›  技术社区  ›  ecoffey

CLR在“抛出”时做什么?

  •  3
  • ecoffey  · 技术社区  · 14 年前

    当我在一个项目中工作时,我对自己说:“嗯,记录一条消息,然后用同样的消息抛出一个异常真的很方便。”。因为这可以让我保留我的“例外是针对特殊情况”的原则,但仍然要确保我们记录了系统中发生错误的详细信息。

    因此产生了:

    public static class LogAndThrow
    {
        public static void Message<TException>(string message) where TException : Exception
        {
            // Log message here
    
            var constructor = 
                typeof(TException).GetConstructor(new[] { typeof(string) });
    
            throw (TException)constructor.Invoke(new[] { message });
        }
    }
    

    然而,作为那种通过反射构建异常的人,我对堆栈跟踪会被日志行消息()行。

    我可以用一些序列化和其他的诡计来替换堆栈跟踪,这些都是非常愚蠢和暴力的。但我想弄清楚这一切只是因为。

    var exception = new Exception();
    throw exception;
    

    在创建异常之后,但在抛出异常之前,唯一设置的是消息。堆栈跟踪等为空。

    以上相当于以下IL:

    .locals init (
        [0] class [mscorlib]System.Exception exception)
    nop 
    newobj instance void [mscorlib]System.Exception::.ctor()
    stloc.0 
    ldloc.0 
    throw 
    

    在我看来,“throw”的IL所做的不仅仅是引用这个引用并把它放在堆栈上。

    有人知道当到达IL'throw'时,运行时对堆栈上的异常做了什么吗?

    这个代码是可怕的和错误的。更像是一个科学实验,而不是任何应该投入生产的东西

    var e = new Exception("message here");
    try
    {
         throw e;
    }
    finally
    {
        // Get the private file _stackTraceString with reflection
        field.SetValue(e, new StackTrace(1).ToString());
    }
    
    1 回复  |  直到 14 年前
        1
  •  5
  •   Kit    6 年前

    为什么不能修改静态方法以返回异常对象并稍后抛出呢。例如

    // Do something
    ...
    // Found error condition, need to throw an exception
    if (error condition)
    {
      throw LogAndThrow.Message("Message goes here");
    }
    

    编辑:AFAIK,没有办法修改堆栈跟踪。有一些方法可以在重新抛出异常时保留原始堆栈跟踪—请参见以下内容 article 为了它。

    另一个编辑

    只是想我会放一些额外的信息和链接。基本上,CLR只在抛出异常时在exception对象中构建堆栈跟踪。这一点在会议上已经提到 MSDN -引用MSDN:

    公共语言运行库(CLR)会在出现错误时更新堆栈跟踪 在应用程序代码中抛出异常(通过使用throw关键字)。 方法,堆栈跟踪包含 以及方法中异常被重试的位置。如果 堆栈跟踪仅包含异常发生的位置 最初抛出

    也提到了这一点 here (作者提到CLR在托管代码中遇到异常时将执行堆栈遍历)。

    关于一些相关的注释(但有点离题),请参阅 this excellent article