Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 检查内部异常的最佳方法?_C#_.net_Exception_Exception Handling - Fatal编程技术网

C# 检查内部异常的最佳方法?

C# 检查内部异常的最佳方法?,c#,.net,exception,exception-handling,C#,.net,Exception,Exception Handling,我知道有时候innerException是空的 因此,以下操作可能会失败: repEvent.InnerException = ex.InnerException.Message; 是否有一种快速检查innerException是否为null的方法?是: if (ex.InnerException == null) { // then it's null } 最简单的解决方案是使用基本条件表达式: repEvent.InnerException = ex.InnerExcepti

我知道有时候innerException是空的

因此,以下操作可能会失败:

 repEvent.InnerException = ex.InnerException.Message; 
是否有一种快速检查innerException是否为null的方法?

是:

if (ex.InnerException == null) {
    // then it's null
}

最简单的解决方案是使用基本条件表达式:

repEvent.InnerException = ex.InnerException == null ? 
    null : ex.InnerException.Message;

这就是你要找的吗

String innerMessage = (ex.InnerException != null) 
                      ? ex.InnerException.Message
                      : "";

到目前为止,答案很好。类似但不同的是,有时存在多个级别的嵌套异常。如果要获取最初抛出的根异常,无论其深度有多深,都可以尝试以下方法:

public static class ExceptionExtensions
{
    public static Exception GetOriginalException(this Exception ex)
    {
        if (ex.InnerException == null) return ex;

        return ex.InnerException.GetOriginalException();
    }
}
在使用中:

repEvent.InnerException = ex.GetOriginalException();

有时InnerException也有一个InnerException,因此您可以对其使用递归函数:

public string GetInnerException(Exception ex)
{
     if (ex.InnerException != null)
     {
        return string.Format("{0} > {1} ", ex.InnerException.Message, GetInnerException(ex.InnerException));
     }
   return string.Empty;
}

真有趣,我找不出有什么问题吗


这是一个老问题,但对未来的读者来说:

除了已经发布的答案之外,我认为正确的方法是(当您可以有多个InnerException时)

如果需要异常实例,应执行以下操作:

repEvent.InnerException = ex.GetBaseException();
如果您仅以这种方式查找邮件:

repEvent.InnerException = ex.GetBaseException().Message;

为什么这些答案中有这么多递归

public static class ExceptionExtensions
{
    public static Exception GetOriginalException(this Exception ex)
    {
        while(ex.InnerException != null)ex = ex.InnerException;
        return ex;
    }
}

这似乎是一种更直接的实现方式。

下面是另一种可能的实现,它附加消息和堆栈跟踪,以便我们将它们填满:

private static Tuple<string, string> GetFullExceptionMessageAndStackTrace(Exception exception)
{
    if (exception.InnerException == null)
    {
        if (exception.GetType() != typeof(ArgumentException))
        {
            return new Tuple<string, string>(exception.Message, exception.StackTrace);
        }
        string argumentName = ((ArgumentException)exception).ParamName;
        return new Tuple<string, string>(String.Format("{0} With null argument named '{1}'.", exception.Message, argumentName ), exception.StackTrace);
    }
    Tuple<string, string> innerExceptionInfo = GetFullExceptionMessageAndStackTrace(exception.InnerException);
    return new Tuple<string, string>(
    String.Format("{0}{1}{2}", innerExceptionInfo.Item1, Environment.NewLine, exception.Message),
    String.Format("{0}{1}{2}", innerExceptionInfo.Item2, Environment.NewLine, exception.StackTrace));
}


[Fact]
public void RecursiveExtractingOfExceptionInformationOk()
{
    // Arrange
    Exception executionException = null;
    var iExLevelTwo = new NullReferenceException("The test parameter is null");
    var iExLevelOne = new ArgumentException("Some test meesage", "myStringParamName", iExLevelTwo);
    var ex = new Exception("Some higher level message",iExLevelOne);

    // Act 
    var exMsgAndStackTrace = new Tuple<string, string>("none","none");
    try
    {
        exMsgAndStackTrace = GetFullExceptionMessageAndStackTrace(ex);
    }
    catch (Exception exception)
    {
        executionException = exception;
    }

    // Assert
    Assert.Null(executionException);

    Assert.True(exMsgAndStackTrace.Item1.Contains("The test parameter is null"));
    Assert.True(exMsgAndStackTrace.Item1.Contains("Some test meesage"));
    Assert.True(exMsgAndStackTrace.Item1.Contains("Some higher level message"));
    Assert.True(exMsgAndStackTrace.Item1.Contains("myStringParamName"));

    Assert.True(!string.IsNullOrEmpty(exMsgAndStackTrace.Item2));

    Console.WriteLine(exMsgAndStackTrace.Item1);
    Console.WriteLine(exMsgAndStackTrace.Item2);
}
私有静态元组GetFullExceptionMessageAndStackTrace(异常)
{
if(exception.InnerException==null)
{
if(exception.GetType()!=typeof(ArgumentException))
{
返回新元组(exception.Message、exception.StackTrace);
}
字符串argumentName=((ArgumentException)exception).ParamName;
返回新元组(String.Format(“{0}带有名为“{1}.”的空参数),exception.Message,argumentName),exception.StackTrace);
}
Tuple innerExceptionInfo=GetFullExceptionMessageAndStackTrace(exception.InnerException);
返回新元组(
String.Format(“{0}{1}{2}”、innerExceptionInfo.Item1、Environment.NewLine、exception.Message),
格式(“{0}{1}{2}”,innerExceptionInfo.Item2,Environment.NewLine,exception.StackTrace));
}
[事实]
public void recursiveExtractionofExceptionFormationOK()递归提取
{
//安排
异常executionException=null;
var iExLevelTwo=新的NullReferenceException(“测试参数为null”);
var iExLevelOne=新的ArgumentException(“某些测试会议”,“myStringParamName”,iExLevelTwo);
var ex=新异常(“某个更高级别的消息”,iExLevelOne);
//表演
var exMsgAndStackTrace=新元组(“无”、“无”);
尝试
{
exMsgAndStackTrace=GetFullExceptionMessageAndStackTrace(ex);
}
捕获(异常)
{
executionException=异常;
}
//断言
Assert.Null(executionException);
True(exMsgAndStackTrace.Item1.Contains(“测试参数为null”);
True(exMsgAndStackTrace.Item1.Contains(“一些测试会议”);
True(exMsgAndStackTrace.Item1.Contains(“某个更高级别的消息”);
True(exMsgAndStackTrace.Item1.Contains(“myStringParamName”));
Assert.True(!string.IsNullOrEmpty(exMsgAndStackTrace.Item2));
Console.WriteLine(exMsgAndStackTrace.Item1);
控制台写入线(exMsgAndStackTrace.Item2);
}
使用C#6.0,您可以使用:

string message=exception.InnerException?.message??“

这行代码类似于:

string message=exception.InnerException==null?“”:exception.InnerException.Message


使用此代码,您可以确保没有丢失任何内部异常消息

catch (Exception exception)
{
   Logger.Error(exception.Message);
   while (exception.InnerException != null)
   {
       exception = exception.InnerException;
       Logger.Error(exception);
   }
}
使用C#6.0,您可以在一行中完成

repEvent.InnerException = ex.InnerException?.Message; 

对于C#6.0的其他功能,单击

,可以使用异常过滤器来获得更精确的瞄准

catch(Exception ex)when(ex.InnerException!=null){…}


请查找更多详细信息

另外,是我自己的问题,还是如果参数被翻转并且
,看起来会更干净一点=改为
==
@Noldorin-对不起,伙计,我回答了这个问题,没有检查我是否是第一个@JL-Noldorin是第一个回答正确的人,请把接受的答案转给他。@Andrew:Heh,不需要道歉。:)我不是一个为一件小事感到不安的人,我只是好奇JL的主要原因。有效,但不适用于多个嵌套的例外情况。您可能希望重新访问您已接受的答案。jrista的答案比其他的好,因为InnerException可以有自己的InnerException。请记住,ToString遍历内部异常并为您组合它们。这是记录日志时一条方便的捷径。完全没有问题,只是Andrew的代码返回了一个字符串。@JL:实际上,mind也返回了一个
字符串。我只是从代码中假设您正在调用
字符串
属性
InnerException
(可能会混淆吗?)。不过没关系@安德鲁:谢谢。尽管我一点也不介意,@Nordorin,啊,我知道问题出在哪里了,我使用字符串是因为异常序列化不好(如果它们确实序列化的话)。@JL:NET framework附带的异常序列化很好,因为它们都有反序列化构造函数。自定义异常可能无法正确序列化,但添加反序列化构造函数并重写GetObjectData非常容易。第三方扩展可以通过序列化代理进行序列化。我完全支持深入挖掘最古老的异常,但这里确实没有理由递归。只要在内部异常不为null的情况下循环就行了。递归是邪恶的还是什么?例如,在实体框架中,深层次的异常是有用的。递归不是邪恶的,但它可能很昂贵,所以如果您不需要它,就不要使用它。在内部异常的情况下,您不需要一直将当前状态推到堆栈上,这样就可以继续您停止的操作,那么为什么要使用递归并为此付出代价呢?还有ca
catch (Exception exception)
{
   Logger.Error(exception.Message);
   while (exception.InnerException != null)
   {
       exception = exception.InnerException;
       Logger.Error(exception);
   }
}
repEvent.InnerException = ex.InnerException?.Message;