Подтвердить что ты не робот

Получение всех сообщений из 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;
    }
}; 
4b9b3361

Ответ 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;
        }
    }
}