调用Attribute()前必须检查xelement是否为NULL,否则易引发nullreferenceexception;attribute()返回null表示属性不存在,空字符串表示属性存在但值为空;带命名空间时需用xnamespace限定,不可直接传字符串名。

用 Attribute() 前先确认元素非 null
直接调 Attribute("name") 而不检查 XElement 是否为 null,是空引用异常最常见来源。比如从 Descendants() 或 Element() 链式调用后立刻取属性,一旦中间某个节点不存在,整个链就崩了。
- 错误写法:
root.Element("User").Attribute("id").Value——Element("User")返回null时,Attribute()就会抛NullReferenceException - 安全写法:先判空,或改用空合并操作符(C# 8+):
root.Element("User")?.Attribute("id")?.Value - 更稳妥的判断方式是显式检查:
var attr = elem.Attribute("status"); if (attr != null) { ... }
Attribute() 返回 null 不等于属性值为空字符串
Attribute() 方法本身不会抛异常,但它返回 null 表示该属性根本不存在;而存在但值为空(如 status="")时,attr.Value 是空字符串,不是 null。很多人混淆这两者,导致逻辑误判。
- 存在但空值:
<item id="123" status=""></item>→elem.Attribute("status").Value == ""成立 - 属性根本不存在:
<item id="123"></item>→elem.Attribute("status") == null - 想统一处理“未设置或为空”的场景,别只判
== null,要加一层String.IsNullOrWhiteSpace(attr?.Value)
用 Attribute() 还是 Attribute(XName)?注意命名空间
如果 xml 带命名空间(比如 SOAP 或 RSS),直接传字符串名会查不到——Attribute("xmlns") 永远返回 null,因为实际是 Attribute(XNamespace.Xmlns + "prefix")。
- 无命名空间时:
elem.Attribute("type")完全 OK - 有默认命名空间时(如
<rss xmlns="http://purl.org/rss/1.0/"></rss>),必须用带命名空间的XName:var ns = "http://purl.org/rss/1.0/"; elem.Attribute(ns + "version") - 别依赖
GetNamespaceOfPrefix()动态获取,容易因作用域失效;建议提前定义好命名空间变量复用
性能敏感场景下避免反复调 Attribute()
每次调 Attribute() 都是一次哈希查找,虽快但非零开销。循环中反复查同一属性(比如解析几百个 <entry></entry> 的 id),不如先存变量。
- 低效写法:
foreach (var e in doc.Descendants("entry")) { console.WriteLine(e.Attribute("id").Value); } - 推荐写法:
foreach (var e in doc.Descendants("entry")) { var idAttr = e.Attribute("id"); if (idAttr != null) Console.WriteLine(idAttr.Value); } - 如果属性名固定且高频使用,可封装成扩展方法,内部做一次查找 + 缓存逻辑(但注意 XElement 不可变,缓存意义不大,重点还是减少重复调用)
最容易被忽略的是命名空间场景下的属性查找失败——它不报错、不抛异常,只是默默返回 null,调试时很难联想到是命名空间问题。遇到“明明 XML 里写了属性却读不到”,第一反应不该是数据源问题,而是检查 XNamespace。