我有一个简单的遗留代码块,它位于一个循环内,它逐个节点地抓取一些可能很糟糕的xml节点,并且由于它没有按预期工作而需要重构:
Try
xmlFrag.LoadXml("<temproot>" & strXMLfragment & "</temproot>")
writer.WriteRaw(strXMLfragment)
Catch ex As Exception
InvalidXML = True
End Try
这个块意味着要做的是检查有效的xml然后写出xml。 实际所做的是检查无效的xml,然后将xml写出 (如果有效)。因此需要将其修复为按预期工作。
我第一次尝试修复:
Try
xmlFrag.LoadXml("<temproot>" & strXMLfragment & "</temproot>")
'writer.WriteRaw(strXMLfragment)
Catch ex As Exception
InvalidXML = True
Finally
writer.WriteRaw(strXMLfragment)
End Try
这适用于我的测试数据,但我担心WriteRaw可能会在其他数据上引发异常。我没有找到关于什么会导致WriteRaw抛出异常以及当Finally block中的代码抛出异常时会发生什么的确凿声明。
所以我试着像这样重写:
Try
xmlFrag.LoadXml("<temproot>" & strXMLfragment & "</temproot>")
Catch ex As Exception
InvalidXML = True
End Try
Try
writer.WriteRaw(strXMLfragment)
Catch
End Try
坦率地说它看起来很难看。有没有更优雅的方式重构这个或第一次尝试是否合适?
答案 0 :(得分:3)
当在Finally
块中引发一个excpetion时,没有什么特别的事情发生:异常会像任何其他异常一样传播出来,而在此finally块中的异常后代码将不被执行。
如果strXMLfragment
为null
或为空字符串(或由于already running asynchronous operation),您的首次尝试将失败。
因此,如果你真的想要处理/吞下所有异常,你将不得不使用两个Try
块。
答案 1 :(得分:3)
为了使其更清洁,您可能希望将您的第一个Try / Catch拉入其自己的私有功能并使其可重复使用:
Private Function TryParseXml(ByVal xml as String) as Boolean
Try
XDocument.Parse(xml)
Return True
Catch ex As Exception
Return False
End Try
End Function
然后将您的writer.WriteRaw调用包装在它自己的Try / Catch中。
Dim myXml = "<temproot>" & strXMLfragment & "</temproot>"
If TryParseXml(myXml) Then
xmlFrag.LoadXml(myXml)
Else
Try
writer.WriteRaw(strXMLfragment)
Catch ex as Exception
' handle exception
End Try
End If
是的,最终这是使用两个Try / Catch块。没有真正解决这个问题的方法是确定Xml是否有效的唯一真正方法是尝试解析它并等待它爆炸。
答案 2 :(得分:2)
最后,我想出了这个非常简单而优雅的重构:
Try
writer.WriteRaw(strXMLfragment)
xmlFrag.LoadXml("<temproot>" & strXMLfragment & "</temproot>")
Catch ex As Exception
InvalidXML = True
End Try
首先执行WriteRaw行,它将始终写出XML,除非它抛出异常。然后LoadXml行可以测试有效性,而不会干扰写出xml。这样,InvalidXML标志按设计设置,不会有任何意外的异常。