What is the correct way to determine exactly what caused an exception, to correct it?
确定导致异常的原因的正确方法是什么,以纠正它?
Consider the code below. I attempt to parse a string of XML, but occasionally, the incoming XML will not be top-level, meaning it needs to be surrounded by a root element.
考虑下面的代码。我尝试解析一串XML,但偶尔,传入的XML不会是*的,这意味着它需要被根元素包围。
Which this happens, the parser throws an XmlException
, but it could throw that for a lot of reasons. I want to catch this one specific reason.
发生这种情况时,解析器会抛出一个XmlException,但由于很多原因它可能会抛出它。我想抓住这个具体原因。
I do this, which I concede is probably not great:
我这样做,我承认可能不是很好:
var doc = new XmlDocument();
try
{
doc.LoadXml(xml);
}
catch(XmlException e)
{
if(e.Message.Contains("multiple root elements"))
{
doc.LoadXml($"<root>{xml}</root>");
}
else
{
throw e;
}
}
This feels like a hack. What is the correct way to do this?
这感觉就像一个黑客。这样做的正确方法是什么?
3 个解决方案
#1
2
you can try to make a switch for XmlException.HResult
as described here:
您可以尝试按照此处所述为XmlException.HResult进行切换:
https://msdn.microsoft.com/en-us/library/system.xml.xmlexception(v=vs.110).aspx
The only thing I am not sure, if it points the the specific exception type (like XmlException) or specific exception "message".
我唯一不确定的是,它是否指向特定的异常类型(如XmlException)或特定的异常“message”。
If this does not help, I think you have no other option than checking for message.
如果这没有帮助,我认为除了检查消息之外别无选择。
EDIT: Also, as was pointed above, you should throw;
instead of throw e;
as the second clears the StackTrace
. ReSharper also warns about this one.
编辑:另外,如上所述,你应该扔;而不是扔e;第二个清除StackTrace。 ReSharper也警告过这个。
#2
2
There is a new feature of C# that allows you to filter exceptions in the catch
clause with when
keyword:
C#有一个新功能,允许您使用when关键字过滤catch子句中的异常:
try
{
}
catch (XmlException ex) when ( ex.Message.Contains(...) )
{
//handle
}
You can use multiple fields to recognize the exception type, like the InnerException
, StackTrace
, and Data
. As @David Hruška suggests, the HResult
property is also a good place to check to recognize the type of the exception
您可以使用多个字段来识别异常类型,例如InnerException,StackTrace和Data。正如@DavidHruška所说,HResult属性也是检查识别异常类型的好地方
The Message
is not the best property to use for the check, as it is usually localized for the built-in types and as a result might look different with other culture setting.
Message不是用于检查的最佳属性,因为它通常针对内置类型进行本地化,因此可能与其他文化设置看起来不同。
#3
1
There are multiple ways to achieve what you're trying to do. Different test frameworks bring their own tools to help with this too. For example, if you're using MSVS Test Framework, the simplest option is to only check for the exception type. In this case you just mark the test method with "ExceptedExceptionAttribute" and specify the expected exception type to be thrown from the method, as follows:
有多种方法可以实现您想要做的事情。不同的测试框架也带来了自己的工具来帮助解决这个问题。例如,如果您使用的是MSVS Test Framework,最简单的选择是仅检查异常类型。在这种情况下,您只需使用“ExceptedExceptionAttribute”标记测试方法,并指定要从方法抛出的预期异常类型,如下所示:
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Action_ThrowsException()
{
// test logic here
}
There is another constructor available, which allows to specify the exact exception message as the second parameter, which is rarely used. You can find the documentation for ExpectedExceptionAttribute in MSDN.
还有另一个可用的构造函数,它允许将确切的异常消息指定为第二个参数,这是很少使用的。您可以在MSDN中找到ExpectedExceptionAttribute的文档。
Another option, where you have more control, would be what was already suggested in the other answers, which can be encapsulated in a helper method as follow:
另一个选项,你有更多的控制权,将是其他答案中已经建议的,可以将其封装在辅助方法中,如下所示:
private static T Throws<T>(Action action) where T : Exception
{
try
{
action();
Assert.Fail();
}
catch (T ex)
{
// This exception was expected.
return ex;
}
}
Using this helper method, you now can have your test method as follows:
使用此辅助方法,您现在可以使用以下测试方法:
[TestMethod]
public void Action_ThrowsException()
{
// test logic here
ArgumentException aex = Throws<ArgumentException>(()=>{
// Test logic here
});
Assert.AreEqual("Expected error message", aex.Message);
}
As you can see, this option provides you with higher flexibility as you can now validate other aspects of the exception explicitly.
如您所见,此选项为您提供了更高的灵活性,因为您现在可以显式验证异常的其他方面。
FYI: The second solution is given as part of the xUnit framework.
仅供参考:第二个解决方案是作为xUnit框架的一部分提供的。
#1
2
you can try to make a switch for XmlException.HResult
as described here:
您可以尝试按照此处所述为XmlException.HResult进行切换:
https://msdn.microsoft.com/en-us/library/system.xml.xmlexception(v=vs.110).aspx
The only thing I am not sure, if it points the the specific exception type (like XmlException) or specific exception "message".
我唯一不确定的是,它是否指向特定的异常类型(如XmlException)或特定的异常“message”。
If this does not help, I think you have no other option than checking for message.
如果这没有帮助,我认为除了检查消息之外别无选择。
EDIT: Also, as was pointed above, you should throw;
instead of throw e;
as the second clears the StackTrace
. ReSharper also warns about this one.
编辑:另外,如上所述,你应该扔;而不是扔e;第二个清除StackTrace。 ReSharper也警告过这个。
#2
2
There is a new feature of C# that allows you to filter exceptions in the catch
clause with when
keyword:
C#有一个新功能,允许您使用when关键字过滤catch子句中的异常:
try
{
}
catch (XmlException ex) when ( ex.Message.Contains(...) )
{
//handle
}
You can use multiple fields to recognize the exception type, like the InnerException
, StackTrace
, and Data
. As @David Hruška suggests, the HResult
property is also a good place to check to recognize the type of the exception
您可以使用多个字段来识别异常类型,例如InnerException,StackTrace和Data。正如@DavidHruška所说,HResult属性也是检查识别异常类型的好地方
The Message
is not the best property to use for the check, as it is usually localized for the built-in types and as a result might look different with other culture setting.
Message不是用于检查的最佳属性,因为它通常针对内置类型进行本地化,因此可能与其他文化设置看起来不同。
#3
1
There are multiple ways to achieve what you're trying to do. Different test frameworks bring their own tools to help with this too. For example, if you're using MSVS Test Framework, the simplest option is to only check for the exception type. In this case you just mark the test method with "ExceptedExceptionAttribute" and specify the expected exception type to be thrown from the method, as follows:
有多种方法可以实现您想要做的事情。不同的测试框架也带来了自己的工具来帮助解决这个问题。例如,如果您使用的是MSVS Test Framework,最简单的选择是仅检查异常类型。在这种情况下,您只需使用“ExceptedExceptionAttribute”标记测试方法,并指定要从方法抛出的预期异常类型,如下所示:
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Action_ThrowsException()
{
// test logic here
}
There is another constructor available, which allows to specify the exact exception message as the second parameter, which is rarely used. You can find the documentation for ExpectedExceptionAttribute in MSDN.
还有另一个可用的构造函数,它允许将确切的异常消息指定为第二个参数,这是很少使用的。您可以在MSDN中找到ExpectedExceptionAttribute的文档。
Another option, where you have more control, would be what was already suggested in the other answers, which can be encapsulated in a helper method as follow:
另一个选项,你有更多的控制权,将是其他答案中已经建议的,可以将其封装在辅助方法中,如下所示:
private static T Throws<T>(Action action) where T : Exception
{
try
{
action();
Assert.Fail();
}
catch (T ex)
{
// This exception was expected.
return ex;
}
}
Using this helper method, you now can have your test method as follows:
使用此辅助方法,您现在可以使用以下测试方法:
[TestMethod]
public void Action_ThrowsException()
{
// test logic here
ArgumentException aex = Throws<ArgumentException>(()=>{
// Test logic here
});
Assert.AreEqual("Expected error message", aex.Message);
}
As you can see, this option provides you with higher flexibility as you can now validate other aspects of the exception explicitly.
如您所见,此选项为您提供了更高的灵活性,因为您现在可以显式验证异常的其他方面。
FYI: The second solution is given as part of the xUnit framework.
仅供参考:第二个解决方案是作为xUnit框架的一部分提供的。