Получение всех сообщений от InnerException(S)?



есть ли способ написать код стиля LINQ "короткая рука" для перехода на все уровни InnerException(S) исключения? Я бы предпочел написать его на месте вместо вызова функции расширения( как показано ниже) или наследования 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;
}
};
530   11  

11 ответов:

к сожалению 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);
}

Вы имеете в виду что-то вроде этого?

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!");

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

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.МММ.ККК.ppp: 8000 / routingservice / router это может принять сообщение. Это часто вызвано неправильным адресом или действием SOAP. Дополнительные сведения см. В разделе InnerException, если имеется.

InnerException: не удается подключиться к удаленному серверу

InnerException: соединение невозможно т. к. конечный компьютер отверг запрос на 127.0.0.1:8000

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

exc.ToString();

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

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

но это в значительной степени вопрос вкуса.

Я так не думаю, исключение не является 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 + ","));

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

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

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

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

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

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

Comments

    Ничего не найдено.