Получать все сообщения от InnerException (s)? - PullRequest
71 голосов
/ 16 февраля 2012

Есть ли какой-нибудь способ написать «сокращенный» код в стиле LINQ для перехода на все уровни InnerException, которые были выброшены в Exception?Я бы предпочел написать его вместо вызова функции расширения (как показано ниже) или наследования класса 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;
    }
}; 

Ответы [ 11 ]

75 голосов
/ 16 февраля 2012

К сожалению, 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);
}
65 голосов
/ 16 февраля 2012

Ты имеешь в виду что-то подобное?

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!");
27 голосов
/ 13 сентября 2013

Как насчет этого кода:

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

18 голосов
/ 06 января 2017

Я знаю, что это очевидно, но, возможно, не для всех.

exc.ToString();

Это пройдет все ваши внутренние исключения и вернет все сообщения, но вместе с трассировкой стека и т. Д.

10 голосов
/ 16 февраля 2012

LINQ обычно используется для работы с коллекциями объектов. Однако, возможно, в вашем случае нет коллекции объектов (кроме графика). Таким образом, хотя некоторый код LINQ может быть возможен, ИМХО он будет довольно запутанным или искусственным.

С другой стороны, ваш пример выглядит как основной пример, где методы расширения на самом деле разумны. Не говоря уже о таких вопросах, как повторное использование, инкапсуляция и т. Д.

Я бы остановился на методе расширения, хотя я мог бы реализовать его таким образом:

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();
}

Но это во многом вопрос вкуса.

8 голосов
/ 04 октября 2018

Вам не нужны методы расширения или рекурсивные вызовы:

try {
  // Code that throws exception
}
catch (Exception e)
{
  var messages = new List<string>();
  do
  {
    messages.Add(e.Message);
    e = e.InnerException;
  }
  while (e != null) ;
  var message = string.Join(" - ", messages);
}
6 голосов
/ 07 июля 2015

Чтобы добавить к другим, вы можете позволить пользователю решать, как разделять сообщения:

    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);
    }
5 голосов
/ 16 февраля 2012

Я так не думаю, исключение не является 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 + ","));
4 голосов
/ 23 апреля 2018

Я просто собираюсь оставить самую краткую версию здесь:

public static class ExceptionExtensions
{
    public static string GetMessageWithInner(this Exception ex) =>
        string.Join($";{ Environment.NewLine }caused by: ",
            GetInnerExceptions(ex).Select(e => $"'{ e.Message }'"));

    public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
    {
        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}
4 голосов
/ 20 июля 2016
    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));
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...