Ответ 1
Вы можете просто напечатать exception.ToString()
- который также будет содержать полный текст для всех вложенных InnerException
s.
Каков правильный способ показать мой полный InnerException
.
Я обнаружил, что некоторые из моих InnerExceptions имеют еще один InnerException
, и это происходит довольно глубоко.
Будет ли InnerException.ToString()
выполнять задание для меня или мне нужно пройти через InnerExceptions
и создать a String
с помощью StringBuilder
?
Вы можете просто напечатать exception.ToString()
- который также будет содержать полный текст для всех вложенных InnerException
s.
Просто используйте exception.ToString()
http://msdn.microsoft.com/en-us/library/system.exception.tostring.aspx
Реализация по умолчанию для ToString по умолчанию получает имя класса, которое выбрасывает текущее исключение, сообщение, результат вызова ToString во внутреннем исключении и результат вызова среды .StackTrace. Если какой-либо из этих элементов имеет значение NULL, его значение не включается в возвращаемую строку.
Если сообщение об ошибке отсутствует или пустая строка (""), то сообщение об ошибке не возвращается. Имя внутреннего исключения и трассировки стека возвращаются только в том случае, если они не являются нулевыми.
exception.ToString() также вызовет .ToString() в этом исключении, внутреннем исключении и т.д....
Я обычно делаю так, чтобы удалить большую часть шума:
void LogException(Exception error) {
Exception realerror = error;
while (realerror.InnerException != null)
realerror = realerror.InnerException;
Console.WriteLine(realerror.ToString())
}
Редактировать: я забыл об этом ответе и удивлен, что никто не указал, что вы можете просто сделать
void LogException(Exception error) {
Console.WriteLine(error.GetBaseException().ToString())
}
@Ответ на вопрос - лучшее решение, когда вам нужна полная информация (все сообщения и трассировка стека) и рекомендуемая.
Однако могут быть случаи, когда вам просто нужны внутренние сообщения, и для этих случаев я использую следующий метод расширения:
public static class ExceptionExtensions
{
public static string GetFullMessage(this Exception ex)
{
return ex.InnerException == null
? ex.Message
: ex.Message + " --> " + ex.InnerException.GetFullMessage();
}
}
Я часто использую этот метод, когда у меня разные слушатели для отслеживания и ведения журнала, и вы хотите иметь разные взгляды на них. Таким образом, у меня может быть один прослушиватель, который отправляет всю ошибку с трассировкой стека по электронной почте в команду dev для отладки с использованием метода .ToString()
, и тот, который записывает журнал в файл с историей всех ошибок, которые происходят каждый день без трассировки стека с помощью метода .GetFullMessage()
.
Чтобы печатать только часть Message
с глубокими исключениями, вы можете сделать что-то вроде этого:
public static string ToFormattedString(this Exception exception)
{
IEnumerable<string> messages = exception
.GetAllExceptions()
.Where(e => !String.IsNullOrWhiteSpace(e.Message))
.Select(e => e.Message.Trim());
string flattened = String.Join(Environment.NewLine, messages); // <-- the separator here
return flattened;
}
public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
yield return exception;
if (exception is AggregateException aggrEx)
{
foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
{
yield return innerEx;
}
}
else if (exception.InnerException != null)
{
foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
{
yield return innerEx;
}
}
}
Это рекурсивно проходит через все внутренние исключения (включая случай с AggregateException
), чтобы распечатать все содержащиеся в них свойства Message
, разделенные переводом строки.
Например
var outerAggrEx = new AggregateException(
"Outer aggr ex occurred.",
new AggregateException("Inner aggr ex.", new FormatException("Number isn't in correct format.")),
new IOException("Unauthorized file access.", new SecurityException("Not administrator.")));
Console.WriteLine(outerAggrEx.ToFormattedString());
Произошло внешнее скопление.
Внутренний агр. Отл.
Номер не в правильном формате.
Несанкционированный доступ к файлам.
Не администратор.
Вам нужно будет прослушать другие свойства исключения для получения более подробной информации. Например, Data
будут иметь некоторую информацию. Вы могли бы сделать:
foreach (DictionaryEntry kvp in exception.Data)
Чтобы получить все производные свойства (Exception
базового класса Exception
), вы можете сделать:
exception
.GetType()
.GetProperties()
.Where(p => p.CanRead)
.Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));
Если вы хотите получить информацию обо всех исключениях, тогда используйте exception.ToString()
. Он будет собирать данные из всех внутренних исключений.
Если вы хотите только оригинальное исключение, тогда используйте exception.GetBaseException().ToString()
. Это даст вам первое исключение, например, самое глубокое внутреннее исключение или текущее исключение, если нет внутреннего исключения.
Пример:
try {
Exception ex1 = new Exception( "Original" );
Exception ex2 = new Exception( "Second", ex1 );
Exception ex3 = new Exception( "Third", ex2 );
throw ex3;
} catch( Exception ex ) {
// ex => ex3
Exception baseEx = ex.GetBaseException(); // => ex1
}
Накапливаться на Nawfal ответ.
при использовании его ответа отсутствовала переменная aggrEx, я ее добавил.
файл ExceptionExtenstions.class:
// example usage:
// try{ ... } catch(Exception e) { MessageBox.Show(e.ToFormattedString()); }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YourNamespace
{
public static class ExceptionExtensions
{
public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
yield return exception;
if (exception is AggregateException )
{
var aggrEx = exception as AggregateException;
foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
{
yield return innerEx;
}
}
else if (exception.InnerException != null)
{
foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
{
yield return innerEx;
}
}
}
public static string ToFormattedString(this Exception exception)
{
IEnumerable<string> messages = exception
.GetAllExceptions()
.Where(e => !String.IsNullOrWhiteSpace(e.Message))
.Select(exceptionPart => exceptionPart.Message.Trim() + "\r\n" + (exceptionPart.StackTrace!=null? exceptionPart.StackTrace.Trim():"") );
string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
return flattened;
}
}
}
Я делаю:
namespace System {
public static class ExtensionMethods {
public static string FullMessage(this Exception ex) {
var msg = ex.Message.Replace(", see inner exception.", "").Trim();
if (ex.InnerException != null) msg += " [" + ex.InnerException.FullMessage() + "]";
return msg;
}
}
}
Если вы хотите отобразить только конкретную строку внутреннего сообщения об исключении, выполните следующие действия:
catch (Exception ex)
{
string[] myex = ex.InnerException.Message.Split('"');
MessageBox.Show(myex[15]);
}
поскольку я использовал myex [15], потому что в основном myex [15] имеет сообщение на правильном английском языке, которое легко понять.