Получение всех сообщений из InnerException (s)?
Есть ли способ написать код "короткой руки" стиля LINQ для перехода на все уровни исключений InnerException исключения? Я бы предпочел написать его вместо того, чтобы называть функцию расширения (как показано ниже) или наследовать класс Exception
.
static class Extensions
{
public static string GetaAllMessages(this Exception exp)
{
string message = string.Empty;
Exception innerException = exp;
do
{
message = message + (string.IsNullOrEmpty(innerException.Message) ? string.Empty : innerException.Message);
innerException = innerException.InnerException;
}
while (innerException != null);
return message;
}
};
Ответы
Ответ 1
К сожалению, LINQ не предлагает методы, которые могли бы обрабатывать иерархические структуры, только коллекции.
У меня есть некоторые методы расширения, которые могли бы помочь в этом. У меня нет точного кода в руке, но они что-то вроде этого:
// all error checking left out for brevity
// a.k.a., linked list style enumerator
public static IEnumerable<TSource> FromHierarchy<TSource>(
this TSource source,
Func<TSource, TSource> nextItem,
Func<TSource, bool> canContinue)
{
for (var current = source; canContinue(current); current = nextItem(current))
{
yield return current;
}
}
public static IEnumerable<TSource> FromHierarchy<TSource>(
this TSource source,
Func<TSource, TSource> nextItem)
where TSource : class
{
return FromHierarchy(source, nextItem, s => s != null);
}
Тогда в этом случае вы можете сделать это, чтобы перечислять через исключения:
public static string GetaAllMessages(this Exception exception)
{
var messages = exception.FromHierarchy(ex => ex.InnerException)
.Select(ex => ex.Message);
return String.Join(Environment.NewLine, messages);
}
Ответ 2
Вы имеете в виду что-то вроде этого?
public static class Extensions
{
public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
{
if (ex == null)
{
throw new ArgumentNullException("ex");
}
var innerException = ex;
do
{
yield return innerException;
innerException = innerException.InnerException;
}
while (innerException != null);
}
}
Таким образом, вы можете LINQ по всей вашей иерархии исключений, например:
exception.GetInnerExceptions().Where(e => e.Message == "Oops!");
Ответ 3
Как насчет этого кода:
private static string GetExceptionMessages(this Exception e, string msgs = "")
{
if (e == null) return string.Empty;
if (msgs == "") msgs = e.Message;
if (e.InnerException != null)
msgs += "\r\nInnerException: " + GetExceptionMessages(e.InnerException);
return msgs;
}
Использование:
Console.WriteLine(e.GetExceptionMessages())
Пример вывода:
В режиме http://nnn.mmm.kkk.ppp:8000/routingservice/router отсутствовала конечная точка, которая могла принять сообщение. Это часто вызвано неправильным адресом или действием SOAP. См. InnerException, если присутствует, для более подробной информации.
InnerException: невозможно подключиться к удаленному серверу
InnerException: соединение не может быть выполнено, потому что целевая машина активно отклонила его 127.0.0.1:8000
Ответ 4
Я знаю, что это очевидно, но, возможно, не для всех.
exc.ToString();
Это будет проходить через все ваши внутренние исключения и будет возвращать все сообщения все вместе.
Ответ 5
LINQ обычно используется для работы с коллекциями объектов. Однако, возможно, в вашем случае нет набора объектов (но графика). Поэтому, даже если бы какой-то код LINQ мог быть возможен, IMHO было бы довольно запутанным или искусственным.
С другой стороны, ваш пример выглядит как пример, где методы расширения действительно разумны. Не говорить о таких проблемах, как повторное использование, инкапсуляция и т.д.
Я бы остался с методом расширения, хотя я мог бы реализовать его так:
public static string GetAllMessages(this Exception ex)
{
if (ex == null)
throw new ArgumentNullException("ex");
StringBuilder sb = new StringBuilder();
while (ex != null)
{
if (!string.IsNullOrEmpty(ex.Message))
{
if (sb.Length > 0)
sb.Append(" ");
sb.Append(ex.Message);
}
ex = ex.InnerException;
}
return sb.ToString();
}
Но это во многом проблема вкуса.
Ответ 6
Чтобы добавить к другим пользователям, вы можете позволить пользователю решить, как отделить сообщения:
public static string GetAllMessages(this Exception ex, string separator = "\r\nInnerException: ")
{
if (ex.InnerException == null)
return ex.Message;
return ex.Message + separator + GetAllMessages(ex.InnerException, separator);
}
Ответ 7
public static string GetExceptionMessage(Exception ex)
{
if (ex.InnerException == null)
{
return string.Concat(ex.Message, System.Environment.NewLine, ex.StackTrace);
}
else
{
// Retira a última mensagem da pilha que já foi retornada na recursividade anterior
// (senão a última exceção - que não tem InnerException - vai cair no último else, retornando a mesma mensagem já retornada na passagem anterior)
if (ex.InnerException.InnerException == null)
return ex.InnerException.Message;
else
return string.Concat(string.Concat(ex.InnerException.Message, System.Environment.NewLine, ex.StackTrace), System.Environment.NewLine, GetExceptionMessage(ex.InnerException));
}
}
Ответ 8
Я так не думаю, что исключение не является IEnumerable, поэтому вы не можете самостоятельно выполнить запрос linq.
Метод расширения для возврата внутренних исключений будет работать следующим образом
public static class ExceptionExtensions
{
public static IEnumerable<Exception> InnerExceptions(this Exception exception)
{
Exception ex = exception;
while (ex != null)
{
yield return ex;
ex = ex.InnerException;
}
}
}
вы можете добавить все сообщения с помощью запроса linq, например:
var allMessageText = string.Concat(exception.InnerExceptions().Select(e => e.Message + ","));
Ответ 9
public static class ExceptionExtensions
{
public static IEnumerable<Exception> GetAllExceptions(this Exception ex)
{
Exception currentEx = ex;
yield return currentEx;
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
yield return currentEx;
}
}
public static IEnumerable<string> GetAllExceptionAsString(this Exception ex)
{
Exception currentEx = ex;
yield return currentEx.ToString();
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
yield return currentEx.ToString();
}
}
public static IEnumerable<string> GetAllExceptionMessages(this Exception ex)
{
Exception currentEx = ex;
yield return currentEx.Message;
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
yield return currentEx.Message;
}
}
}