如何将StackFrame集合转换为字符串?

时间:2015-04-01 17:17:58

标签: c# exception-handling stack-trace tostring stackframe

我有一个IEnumerable<System.Diagnostics.StackFrame> frames存储一些自定义StackFrame。 我想将其转换为类似StackTrace.ToString()格式的字符串类型。 例如:

   at TestStackTrace.Form1.button2_Click(Object sender, EventArgs e) in 
d:\Programming\temp\TestStackTrace\TestStackTrace\Form1.cs:line 66
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)

2 个答案:

答案 0 :(得分:3)

使用stateprinter框架。它可以将对象图转换为字符串,甚至可以自动执行测试的断言部分。见https://github.com/kbilsted/StatePrinter/blob/master/doc/AutomatingUnitTesting.md

制作字符串

string s = new Stateprinter().PrintObject(stackframe)

答案 1 :(得分:1)

我已使用Microsoft Reference Source反映(mscorlib)。system\diagnostics\stacktrace.cs代码,并了解了将{4}}方法转换为字符串的方法。 所以,有了这个,我可以编写一个没有依赖的函数。

public static string StackFramesToString(this StackFrame[] frames, int numMethodsToSkip = 0)
{
    bool displayFilenames = true;   // we'll try, but demand may fail
    String word_At = "at";
    String inFileLineNum = "in {0}:line {1}";

    bool fFirstFrame = true;
    StringBuilder sb = new StringBuilder(255);
    for (int iFrameIndex = 0; iFrameIndex < frames.Count(); iFrameIndex++)
    {
        StackFrame sf = GetFrame(iFrameIndex, frames, numMethodsToSkip);
        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 = "<UnknownType>";
                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();
                }
                catch 
                {
                    // 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());
                }
            }
        }
    }

    return sb.ToString();
}


public static StackFrame GetFrame(int index, StackFrame[] frames, int numMethodsToSkip)
{
    if ((frames != null) && (index < frames.Count()) && (index >= 0))
        return frames[index + numMethodsToSkip];

    return null;
}