博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Exception的ToString()方法究竟返回的是什么
阅读量:6734 次
发布时间:2019-06-25

本文共 12651 字,大约阅读时间需要 42 分钟。

最近项目上线后遇到exception没有堆栈信息。所以跟踪一下 源码,其中主要的code如下:

// Returns the stack trace as a string.  If no stack trace is        // available, null is returned.        public virtual String StackTrace        {#if FEATURE_CORECLR            [System.Security.SecuritySafeCritical] #endif            get             {                // By default attempt to include file and line number info                return GetStackTrace(true);            }        }        // Computes and returns the stack trace as a string        // Attempts to get source file and line number information if needFileInfo        // is true.  Note that this requires FileIOPermission(PathDiscovery), and so        // will usually fail in CoreCLR.  To avoid the demand and resulting        // SecurityException we can explicitly not even try to get fileinfo.        #if FEATURE_CORECLR        [System.Security.SecurityCritical] // auto-generated        #endif        private string GetStackTrace(bool needFileInfo)        {            string stackTraceString = _stackTraceString;            string remoteStackTraceString = _remoteStackTraceString;#if !FEATURE_CORECLR            if (!needFileInfo)            {                // Filter out file names/paths and line numbers from _stackTraceString and _remoteStackTraceString.                // This is used only when generating stack trace for Watson where the strings must be PII-free.                stackTraceString = StripFileInfo(stackTraceString, false);                remoteStackTraceString = StripFileInfo(remoteStackTraceString, true);            }#endif // !FEATURE_CORECLR            // if no stack trace, try to get one            if (stackTraceString != null)            {                return remoteStackTraceString + stackTraceString;            }            if (_stackTrace == null)            {                return remoteStackTraceString;            }            // Obtain the stack trace string. Note that since Environment.GetStackTrace            // will add the path to the source file if the PDB is present and a demand            // for FileIOPermission(PathDiscovery) succeeds, we need to make sure we             // don't store the stack trace string in the _stackTraceString member variable.            String tempStackTraceString = Environment.GetStackTrace(this, needFileInfo);            return remoteStackTraceString + tempStackTraceString;         }    #if FEATURE_CORECLR        [System.Security.SecuritySafeCritical] #endif        public override String ToString()        {            return ToString(true, true);        }        #if FEATURE_CORECLR        [System.Security.SecurityCritical] // auto-generated        #endif        private String ToString(bool needFileLineInfo, bool needMessage) {            String message = (needMessage ? Message : null);            String s;            if (message == null || message.Length <= 0) {                s = GetClassName();            }            else {                s = GetClassName() + ": " + message;            }            if (_innerException!=null) {                s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine +                 "   " + Environment.GetResourceString("Exception_EndOfInnerExceptionStack");            }            string stackTrace = GetStackTrace(needFileLineInfo);            if (stackTrace != null)            {                s += Environment.NewLine + stackTrace;            }            return s;        }

Exception的StackTrace属性只返回当前对象的站信息,toString方法首先需要获取当前的Message,然后获取内部exception的tostring方法,最后获取 GetStackTrace方法的返回值,该方法主要内容来源于 Environment.GetStackTrace方法,其实现code如下:

internal static String GetStackTrace(Exception e, bool needFileInfo)        {            // Note: Setting needFileInfo to true will start up COM and set our            // apartment state.  Try to not call this when passing "true"             // before the EE's ExecuteMainMethod has had a chance to set up the            // apartment state.  --             StackTrace st;            if (e == null)                st = new StackTrace(needFileInfo);            else                st = new StackTrace(e, needFileInfo);            // Do no include a trailing newline for backwards compatibility            return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );        }

调用的是StackTrace的tostring方法,其实现如下:

internal String ToString(TraceFormat traceFormat)        {            bool displayFilenames = true;   // we'll try, but demand may fail            String word_At = "at";            String inFileLineNum = "in {0}:line {1}";            if(traceFormat != TraceFormat.NoResourceLookup)            {                word_At = Environment.GetResourceString("Word_At");                inFileLineNum = Environment.GetResourceString("StackTrace_InFileLineNumber");            }                        bool fFirstFrame = true;            StringBuilder sb = new StringBuilder(255);            for (int iFrameIndex = 0; iFrameIndex < m_iNumOfFrames; iFrameIndex++)            {                StackFrame sf = GetFrame(iFrameIndex);                MethodBase mb = sf.GetMethod();                if (mb != null)                {                    // We want a newline at the end of every line except for the last                    if (fFirstFrame)                        fFirstFrame = false;                    else                        sb.Append(Environment.NewLine);                                        sb.AppendFormat(CultureInfo.InvariantCulture, "   {0} ", word_At);                    Type t = mb.DeclaringType;                     // if there is a type (non global method) print it                    if (t != null)                    {                                                           sb.Append(t.FullName.Replace('+', '.'));                        sb.Append(".");                    }                    sb.Append(mb.Name);                    // deal with the generic portion of the method                    if (mb is MethodInfo && ((MethodInfo)mb).IsGenericMethod)                    {                        Type[] typars = ((MethodInfo)mb).GetGenericArguments();                        sb.Append("[");                        int k=0;                        bool fFirstTyParam = true;                        while (k < typars.Length)                        {                            if (fFirstTyParam == false)                                sb.Append(",");                            else                                fFirstTyParam = false;                            sb.Append(typars[k].Name);                                         k++;                        }                           sb.Append("]");                        }                    // arguments printing                    sb.Append("(");                    ParameterInfo[] pi = mb.GetParameters();                    bool fFirstParam = true;                    for (int j = 0; j < pi.Length; j++)                    {                        if (fFirstParam == false)                            sb.Append(", ");                        else                            fFirstParam = false;                        String typeName = "
"; if (pi[j].ParameterType != null) typeName = pi[j].ParameterType.Name; sb.Append(typeName + " " + pi[j].Name); } sb.Append(")"); // source location printing if (displayFilenames && (sf.GetILOffset() != -1)) { // If we don't have a PDB or PDB-reading is disabled for the module, // then the file name will be null. String fileName = null; // Getting the filename from a StackFrame is a privileged operation - we won't want // to disclose full path names to arbitrarily untrusted code. Rather than just omit // this we could probably trim to just the filename so it's still mostly usefull. try { fileName = sf.GetFileName(); }#if FEATURE_CAS_POLICY catch (NotSupportedException) { // Having a deprecated stack modifier on the callstack (such as Deny) will cause // a NotSupportedException to be thrown. Since we don't know if the app can // access the file names, we'll conservatively hide them. displayFilenames = false; }#endif // FEATURE_CAS_POLICY catch (SecurityException) { // If the demand for displaying filenames fails, then it won't // succeed later in the loop. Avoid repeated exceptions by not trying again. displayFilenames = false; } if (fileName != null) { // tack on " in c:\tmp\MyFile.cs:line 5" sb.Append(' '); sb.AppendFormat(CultureInfo.InvariantCulture, inFileLineNum, fileName, sf.GetFileLineNumber()); } }#if FEATURE_EXCEPTIONDISPATCHINFO if (sf.GetIsLastFrameFromForeignExceptionStackTrace()) { sb.Append(Environment.NewLine); sb.Append(Environment.GetResourceString("Exception_EndStackTraceFromPreviousThrow")); }#endif // FEATURE_EXCEPTIONDISPATCHINFO } } if(traceFormat == TraceFormat.TrailingNewLine) sb.Append(Environment.NewLine); return sb.ToString(); }

这个方法最主要的还是   StackFrame sf = GetFrame(iFrameIndex);   它返回跟踪栈的信息。跟踪栈的信息主要来源于StackTrace的构造函数

public StackTrace(Exception e, bool fNeedFileInfo)        {            if (e == null)                throw new ArgumentNullException("e");            Contract.EndContractBlock();            m_iNumOfFrames = 0;            m_iMethodsToSkip = 0;            CaptureStackTrace(METHODS_TO_SKIP, fNeedFileInfo, null, e);        }

核心实现CaptureStackTrace code如下:

private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread,                                       Exception e)        {            m_iMethodsToSkip += iSkip;                StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread);                GetStackFramesInternal(StackF, 0, e);                m_iNumOfFrames = StackF.GetNumberOfFrames();            if (m_iMethodsToSkip > m_iNumOfFrames)                m_iMethodsToSkip = m_iNumOfFrames;            if (m_iNumOfFrames != 0)            {                frames = new StackFrame[m_iNumOfFrames];                for (int i = 0; i < m_iNumOfFrames; i++)                {                    bool fDummy1 = true;                    bool fDummy2 = true;                    StackFrame sfTemp = new StackFrame(fDummy1, fDummy2);                    sfTemp.SetMethodBase(StackF.GetMethodBase(i));                    sfTemp.SetOffset(StackF.GetOffset(i));                    sfTemp.SetILOffset(StackF.GetILOffset(i));#if FEATURE_EXCEPTIONDISPATCHINFO                    sfTemp.SetIsLastFrameFromForeignExceptionStackTrace(StackF.IsLastFrameFromForeignExceptionStackTrace(i));#endif // FEATURE_EXCEPTIONDISPATCHINFO                    if (fNeedFileInfo)                    {                        sfTemp.SetFileName(StackF.GetFilename (i));                        sfTemp.SetLineNumber(StackF.GetLineNumber(i));                        sfTemp.SetColumnNumber(StackF.GetColumnNumber(i));                    }                     frames[i] = sfTemp;                }                // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace,                // but this is not desired if building a stack trace from an exception.                if (e == null)                    m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames);                m_iNumOfFrames -= m_iMethodsToSkip;                if (m_iNumOfFrames < 0)                   {                       m_iNumOfFrames = 0;                   }            }            // In case this is the same object being re-used, set frames to null            else                frames = null;        }

顺便提一下,VS在release模式下是可以调试的,也可以获取堆栈信息。

 

转载地址:http://fofqo.baihongyu.com/

你可能感兴趣的文章
设计模式-观察者模式
查看>>
Java内存与垃圾回收机制
查看>>
阿里数据库内核月报:2017年02月
查看>>
那些前端工作中遇到的坑(01)
查看>>
iOS 常用图片格式判断 (Swift)
查看>>
【iOS基础】layoutSubviews什么时候调用
查看>>
干蹦轮播图的布局摘要
查看>>
前端面试题目总结-js相关
查看>>
ETH官方客户端Geth的使用(一)
查看>>
春招落下帷幕——期待与eBay相遇
查看>>
CORS 理解(不要那么多术语)
查看>>
Flask框架
查看>>
Python通用编程 - 第五章:文件处理
查看>>
996 icu 不算什么?生活在继续
查看>>
Page Object设计模式
查看>>
mysql数据库开发常见问题及优化
查看>>
阿里云前端周刊 - 第 19 期
查看>>
【区块链】Cryptium Labs中国见面会——北京站
查看>>
强大的API测试工具Hitchhiker v0.9 基于UI的断言测试,回顾2017
查看>>
GCD 的一点疑惑与自解
查看>>