我经常有一个要求:
当然,exception.Message
的信息太少了。
但是exception.ToString()
有点太多而且不可读:
System.NotImplementedException: Die Methode oder der Vorgang ist nicht implementiert.
bei ConsoleApplication1.Program.Second() in C:\..\Program.cs:Line 48.
bei ConsoleApplication1.Program.First() in C:\..\Program.cs:Line 43.
bei ConsoleApplication1.Program.Main(String[] args) in C:\..\Program.cs:Line 21.
我的想法是一个包含最相关信息的单一行,如下所示:
System.NotImplementedException: Die Methode oder der Vorgang ist nicht implementiert {ConsoleApplication1.Program.Main(String[] args)[21] -> ConsoleApplication1.Program.First()[43] -> ConsoleApplication1.Program.Second()[48]}
最好的方法是什么?
我意识到我可以从TargetSite属性获得最深的异常导致方法名称。
但是如何获取方法呢?最重要的是:如何获得行号?
答案 0 :(得分:1)
您可以将来自exception.Message
的信息与Environment.StackTrace
相结合(例如,拆分成行并仅使用最后几行)或使用Diagnostics.StackTrace
类来获取您需要的信息。祝你好运!
答案 1 :(得分:1)
就例外情况而言,TMI是YMMV的事情。 我会选择Exception.Message + StackTrace。 (几乎是ToString()似乎打印)
如果您真的认为您只需要用户代码中的最后几个函数/仅函数,则可以拆分堆栈跟踪并仅获取与您的类/程序集名称匹配的行。
IMO更多信息总是很好,在阅读过程中没有节省空间/花时间跳过几行是值得开发人员挫折/花费的时间
哇,这段代码发生了什么,我希望我从堆栈跟踪中再添加一行。
要获取行号,您需要pdb文件信息: C# Exceptions Not Giving Line Numbers
答案 2 :(得分:0)
根据@data的链接,我制作了自己的方法,符合我的要求。
public static class ExceptionExtensions
{
/// <summary>
/// Return a compact exception format for logging
/// </summary>
/// <remarks>
/// In a single line the exception will contains the most relevant information like
/// Excepition type and message, the call stack methods and lines
/// Note: call stack is only available in Debug, Release will not contain these information
/// </remarks>
/// <param name="ex"></param>
/// <returns></returns>
/// <example>System.NotImplementedException: NotImplementedException (OwnLib.WoohooClass.ThisIsTheBestMethodEver()[13] => ConsoleApplication1.OwnClass.CallMeAClass()[13] => ConsoleApplication1.Program.Second(System.TimeSpan)[68] => ConsoleApplication1.Program.First()[57] => ConsoleApplication1.Program.Main(System.String[])[25])</example>
public static string ToCompactString(this Exception ex)
{
var stack = new List<string>();
var stackTrace = new StackTrace(ex, true);
for (int i = 0; i < stackTrace.FrameCount; i++)
{
StackFrame sf = stackTrace.GetFrame(i);
var method = sf.GetMethod();
stack.Add(string.Format("{0}[{1}]",
method.ToString().SubstringFromMatch(method.Name, true).Replace(method.Name, string.Format("{0}.{1}", method.ReflectedType.FullName, method.Name)),
sf.GetFileLineNumber()));
}
return string.Format("{0}: {1} ({2})", ex.GetType(), ex.Message, stack.GetDelimiterSeperatedList(" => "));
}
}
//Helper methods
public static class StringExtensions
{
/// <summary>
/// Substring for a searched string. takes the whole string from the match and cuts before.
/// </summary>
/// <param name="searchString">string to search within</param>
/// <param name="searchedString">string to search for</param>
/// <param name="includeMatch"><c>true</c> = with searchString, <c>false</c> = without</param>
/// <param name="count">which time to found (0 = first)</param>
/// <returns>a substring for a match, the whole string when no match</returns>
public static string SubstringFromMatch(this string searchString, string searchedString, bool includeMatch, int count = 0)
{
if (searchString.Contains(searchedString))
{
var index = searchString.IndexOf(searchedString, count, StringComparison.Ordinal) + (includeMatch ? 0 : searchedString.Length);
return searchString.Substring(index, searchString.Length - index);
}
return searchString;
}
/// <summary>
/// Returns a list auf values, concatted by a delimiter like ",", e.g. "1,2,abc,cde"
/// </summary>
/// <remarks>a maximum of 999 items could be seperated</remarks>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="delimiter">a delimiter used to seperate the items</param>
/// <example>"," => "item1,item2,item3"; " - " "item1 - item2 - item3"</example>
public static string GetDelimiterSeperatedList<T>(this ICollection<T> list, string delimiter)
{
if (list != null && list.Count > 0)
{
var seperatedList = String.Empty;
var listCounter = 0;
foreach (var id in list)
{
seperatedList += String.Format("{0}{1}", id, delimiter);
if (listCounter++ >= 999) break;
}
return seperatedList.Remove(seperatedList.LastIndexOf(delimiter, StringComparison.Ordinal));
}
return null;
}
}
示例输出如下所示:
System.NotImplementedException:你有forgotton做某事(AnotherLib.WoohooClass.ThisIsTheMostUselessMethodEver()[13] =&gt; ConsoleApplication1.AnotherClass.CallMeAClass()[13] =&gt; ConsoleApplication1.Program.Third(System.TimeSpan) [68] =&gt; ConsoleApplication1.Program.Second()[63] =&gt; ConsoleApplication1.Program.First()[57] =&gt; ConsoleApplication1.Program.Main(System.String [])[25])
顺便说一下:我还验证了上面的解决方案的时间测量和正常的exception.ToString()
方法。有趣的是,没有显着差异。
谢谢你的帮助。