Obtener todos los mensajes de InnerException(s)?

Es allí cualquier manera de escribir una LINQ estilo «corto la mano» código para caminar a todos los niveles de InnerException(s) de Excepción? Yo prefiero escribir en su lugar en lugar de llamar a una función de extensión (como abajo) o heredar la Exception clase.

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;
    }
}; 
  • ¿Puedo preguntar por qué quieres utilizar algo más que los métodos de Extensión? El código se ve bien para mí, y es reutilizable en todas partes en el código.
  • Aunque usted no lo desea construir los mensajes de la forma que es ahora…
  • Sí, pero ¿cuál es el problema con el concepto de «extensiones del método»?
  • Para ser honesto, realmente no entiendo tu pregunta… usted acaba de mencionar que el código se ve «bien» cuando es defectuosa.
  • Sólo ten cuidado en mente AggregateExceptions se comportan poco diferente. Usted tendrá que caminar a través de InnerExceptions propiedad en su lugar. Proporciona un práctico método de extensión aquí: stackoverflow.com/a/52042708/661933 para cubrir ambos casos.
InformationsquelleAutor Jimmy | 2012-02-16

11 Kommentare

  1. 80

    Lamentablemente LINQ no ofrece métodos que podrían proceso de estructuras jerárquicas, sólo colecciones.

    De hecho tengo algunos métodos de extensión que podría ayudar a hacer esto. No tengo el código exacto en la mano, pero son algo como esto:

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

    A continuación, en este caso, usted puede hacer esto a enumerar las excepciones:

    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. 73

    Te refieres a algo como esto?

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

    De esta forma se podría LINQ largo de toda su jerarquía de excepciones, como este:

    exception.GetInnerExceptions().Where(e => e.Message == "Oops!");
    • Mucho más limpio que la solución propuesta
  3. 28

    Cómo acerca de este código:

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

    Uso:

    Console.WriteLine(e.GetExceptionMessages())

    Ejemplo de salida:

    No había extremo de la escucha en http://nnn.mmm.kkk.ppp:8000/routingservice/router que podría aceptar el mensaje. Esto es a menudo causada por una dirección incorrecta o JABÓN de acción. Ver InnerException, si está presente, para obtener más detalles.

    InnerException: no se puede conectar con el servidor remoto

    InnerException: No se pudo establecer conexión ya que el equipo de destino ha denegado activamente dicha 127.0.0.1:8000

    • Usted realmente debe considerar el uso de StringBuilder aquí. También OMI método de extensión debe lanzar NullReferenceException cuando se invoca en una referencia nula.
  4. 20

    Sé que esto es obvio, pero tal vez no para todos.

    exc.ToString();

    Esto va a ir a través de todos sus excepciones internas y devuelve todos los mensajes, sino que, junto con el seguimiento de la pila etc.

    • Yeh muy bien eso si su feliz para vivir con toda la pila completa de seguimiento que conseguir blatted con ToString. Muchas veces no se adecuan al contexto e.g si el mensaje es ir a un usuario. Por otro lado el Mensaje NO da al interior de Mensaje de excepción (a diferencia de ToString que hace recurse). Lo que más a menudo queremos es nulo FullMessage que es todo el mensaje de los padres y excepciones internas.
  5. 13

    Usted no necesita métodos de extensión o llamadas recursivas:

    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);
    }
    • Genial! Deseo que yo había pensado de él.
  6. 10

    LINQ se utiliza generalmente para trabajar con colecciones de objetos. Sin embargo, podría decirse que, en su caso no hay colección de objetos (pero un gráfico). Así que, aunque algunos de LINQ código podría ser posible, en mi humilde opinión sería bastante complicado o artificial.

    Por otro lado, su ejemplo se ve como un primer ejemplo, donde la extensión de los métodos son realmente razonables. No hablar de temas como la reutilización, la encapsulación, etc.

    Me quedaría con un método de extensión, aunque podría haber implementado de esa manera:

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

    Pero que es en gran medida una cuestión de gusto.

  7. 6

    Yo no lo creo, la excepción no es un IEnumerable así que usted no puede realizar una consulta de linq contra uno por su cuenta.

    Un método de extensión para devolver el interior excepciones trabajo como este

    public static class ExceptionExtensions
    {
        public static IEnumerable<Exception> InnerExceptions(this Exception exception)
        {
            Exception ex = exception;
    
            while (ex != null)
            {
                yield return ex;
                ex = ex.InnerException;
            }
        }
    }

    entonces, usted puede anexar todos los mensajes a través de una consulta linq como este:

    var allMessageText = string.Concat(exception.InnerExceptions().Select(e => e.Message + ","));
  8. 6

    Para agregar a los demás, puede que desee que el usuario pueda decidir sobre cómo separar los mensajes:

        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);
        }
  9. 5
        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));
            }
        }
  10. 4

    Voy a salir de la manera más concisa versión aquí:

    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;
            }
        }
    }
  11. 3
    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;
            }
        }
    }

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea