我有一个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)
答案 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;
}