XDocument.Root : 可能 System.NullReferenceException

XDocument.Root : Possible System.NullReferenceException

看起来 R# 正在检测以下代码中可能存在的空引用:

var importedDoc = XDocument.Parse(importedXml);
var importedElements = importedDoc.Root.Elements().ToList();

访问importedDoc.Root时属性。尴尬的是,现在我想对我的方法进行单元测试,但我无法通过 importedXml,因此结果 XDocument.Root 会抛出 NullReferenceException。如果是这种情况,我已经添加了空检查代码以抛出异常并且我想覆盖该分支:

if (importedDoc.Root == null)
    throw new NullReferenceException("There is no root element");

任何人都可以提供实现此目的的方法,或者如果不能,至少解释一下 R# 是如何产生此代码警告的? Root 属性 是否未标记为 [NotNull] 因为可能有不同的构造 XDocument 的方法,其中 Root 实际上是null?如果是这样,这不是 System.Xml.Linq 中的错误吗?

resharper 不知道任何类型的运行时检查 XDocument.Parse 可能会或可能不会执行以确保存在根级元素。它只是将 XDocument.Parse 视为可能 return 为 null 的函数的调用,并建议您应该在实际使用 returned 对象的成员的地方测试 null 条件。

因为 importedDoc.Root 实际上不能为空,因为 XDocument.Parse 在这种情况下进行解析时会抛出异常,您可以通过注释关闭 resharper 警告

// ReSharper disable once PossibleNullReferenceException
var importedElements = importedDoc.Root.Elements().ToList();

或者您可以自己添加 null 检查并重新引发异常,如果您希望这样让 resharper 满意的话:

var importedDoc = XDocument.Parse(importedXml);
var importedElements = importedDoc?.Root?.Elements().ToList() ?? new List<XElement>();

if (importedElements.Count == 0) throw new InvalidOperationException("No root");

或者你可以完全忽略整个事情,因为你知道这个特定的警告在这种情况下并不完全有效。

您收到此警告的具体原因是 R# 对 XDocument.Root 的外部注释说它可以为空。 R#s external annotations are open-sourced, so you can see the item for yourself here on github(撰写本文时为第 214 行)。

现在,在这个特定的代码路径中(通过 Parse 创建 XDocument),反编译代码的检查表明 Root 在这种情况下 永远不能是 null,因为如果 XDocument.Load 在加载完成后发现 Rootnull 就会抛出;但这并不是说 Root 永远 永远不会 成为 null。因此,一次性的 R# 警告抑制似乎是最合适的。