C# 从 InnerException(s) 获取所有消息?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9314172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 06:51:32  来源:igfitidea点击:

Getting all messages from InnerException(s)?

c#c#-4.0

提问by Jimmy

Is there any way to write a LINQ style "short hand" code for walking to all levels of InnerException(s) of Exception thrown? I would prefer to write it in place instead of calling an extension function (as below) or inheriting the Exceptionclass.

有没有办法编写一个 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;
    }
}; 

采纳答案by Jeff Mercado

Unfortunately LINQ doesn't offer methods that could process hierarchical structures, only collections.

不幸的是,LINQ 不提供可以处理层次结构的方法,只有集合。

I actually have some extension methods that could help do this. I don't have the exact code in hand but they're something like this:

我实际上有一些扩展方法可以帮助做到这一点。我手头没有确切的代码,但它们是这样的:

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

Then in this case you could do this to enumerate through the exceptions:

那么在这种情况下,您可以这样做以枚举异常:

public static string GetaAllMessages(this Exception exception)
{
    var messages = exception.FromHierarchy(ex => ex.InnerException)
        .Select(ex => ex.Message);
    return String.Join(Environment.NewLine, messages);
}

回答by k.m

You mean something like this?

你的意思是这样的?

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

This way you could LINQ over your entire exceptions hierarchy, like this:

通过这种方式,您可以在整个异常层次结构中使用 LINQ,如下所示:

exception.GetInnerExceptions().Where(e => e.Message == "Oops!");

回答by Christian.K

LINQ is generally used to work with collections of objects. However, arguably, in your case there is no collection of objects (but a graph). So even though some LINQ code might be possible, IMHO it would be rather convoluted or artificial.

LINQ 通常用于处理对象集合。但是,可以说,在您的情况下,没有对象集合(而是图形)。因此,即使某些 LINQ 代码可能是可能的,恕我直言,它会相当复杂或人为。

On the other hand, your example looks like a prime example where extension methods are actually reasonable. Not to speak of issues like reuse, encapsulation, etc.

另一方面,您的示例看起来像是一个主要示例,其中扩展方法实际上是合理的。更不用说重用、封装等问题了。

I would stay with an extension method, although I might have implemented it that way:

我会继续使用扩展方法,尽管我可能已经这样实现了:

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

But that is largely an issue of taste.

但这在很大程度上是一个品味问题。

回答by Trevor Pilley

I don't think so, exception is not an IEnumerable so you can't perform a linq query against one on its own.

我不这么认为,异常不是一个 IEnumerable,所以你不能对它自己执行 linq 查询。

An extension method to return the inner exceptions would work like this

返回内部异常的扩展方法将像这样工作

public static class ExceptionExtensions
{
    public static IEnumerable<Exception> InnerExceptions(this Exception exception)
    {
        Exception ex = exception;

        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}

you could then append all the messages using a linq query like this:

然后,您可以使用如下 linq 查询附加所有消息:

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

回答by Kishore Kumar

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

回答by Vlad Gonchar

How about this code:

这段代码怎么样:

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

Usage:

用法:

Console.WriteLine(e.GetExceptionMessages())

Example of output:

输出示例:

There was no endpoint listening at http://nnn.mmm.kkk.ppp:8000/routingservice/routerthat could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

http://nnn.mmm.kkk.ppp:8000/routingservice/router上没有侦听端点可以接受消息。这通常是由不正确的地址或 SOAP 操作引起的。有关更多详细信息,请参阅 InnerException(如果存在)。

InnerException: Unable to connect to the remote server

内部异常:无法连接到远程服务器

InnerException: No connection could be made because the target machine actively refused it 127.0.0.1:8000

InnerException:无法建立连接,因为目标机器主动拒绝它 127.0.0.1:8000

回答by Shaggy

To add to others, you may want to let the user decide on how to separate the messages:

要添加到其他人,您可能希望让用户决定如何分隔消息:

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

回答by Ronaldo Rodrigues Lagoeiro Mar

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

回答by Ji?í Herník

I know this is obvious, but maybe not for all.

我知道这很明显,但也许不是所有人。

exc.ToString();

This will go through all your inner exceptions and returns all messages, but together with stack trace etc.

这将遍历您所有的内部异常并返回所有消息,但与堆栈跟踪等一起。

回答by Dmitry Karpenko

I'm just going to leave the most concise version here:

我只想在这里留下最简洁的版本:

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