我有: 包含一些元素的XML。 可以在此XML中定义的子元素,也可以不在此XML中定义。 需要在子元素存在时提取子元素的值。
如何在不抛出对象引用错误的情况下获取值?
例如:
string sampleXML = "<Root><Tag1>tag1value</Tag1></Root>";
//Pass in <Tag2> and the code works:
//string sampleXML = "<Root><Tag1>tag1value</Tag1><Tag2>tag2Value</Tag2></Root>";
XDocument sampleDoc = XDocument.Parse(sampleXML);
//Below code is in another method, the 'sampleDoc' is passed in. I am hoping to change only this code
XElement sampleEl = sampleDoc.Root;
string tag1 = String.IsNullOrEmpty(sampleEl.Element("Tag1").Value) ? "" : sampleEl.Element("Tag1").Value;
//NullReferenceException:
//Object reference not set to an instance of an object.
string tag2 = String.IsNullOrEmpty(sampleEl.Element("Tag2").Value) ? "" : sampleEl.Element("Tag2").Value;
答案 0 :(得分:10)
您可以使用null-coalescing-operator获取快捷方式:
string tag1= (string)sampleEl.Element("Tag1") ?? string.Empty;
这也使用了LINQ to XML允许强制转换操作获取元素值(在本例中为强制转换为字符串)的事实,但如果元素不存在则返回null
。
答案 1 :(得分:3)
您需要检查null
才能阻止它们。鉴于您正在使用的重复模式,我只会将其分解为扩展方法。
public static string GetElementValue(this XElement parent, string elementName) {
if (parent == null) {
return string.Empty;
}
var element = parent.Element(elementName);
if (element == null || element.Value == null) {
return string.Empty;
}
return element.Value;
}
现在您的上述代码可以替换为以下
string tag1 = sampleEl.GetElementValue("Tag1");
string tag2 = sampleEl.GetElementValue("Tag2");
答案 2 :(得分:3)
C#三元运算符非常适合:
string tag2 = sampleEl.Element("Tag2") == null ? "" : sampleEl.Element("Tag2").Value;
答案 3 :(得分:2)
首先你应该检查文档是否为null,记住你正在访问.Value,这会抛出一个空引用异常,所以在你申请之前.value做一个测试:
if (sampleEl != null)
//now apply .value
或三元:
string tag2 = sampleEl.Element("Tag2") != null ? sampleEL.Element("Tag2").Value : String.Empty
然后您的代码变为:
string sampleXML = "<Root><Tag1>tag1value</Tag1></Root>";
//Pass in <Tag2> and the code works:
//string sampleXML = "<Root><Tag1>tag1value</Tag1><Tag2>tag2Value</Tag2></Root>";
XDocument sampleDoc = XDocument.Parse(sampleXML);
//Below code is in another method, the 'sampleDoc' is passed in. I am hoping to change only this code
XElement sampleEl = sampleDoc.Root;
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : String.Empty;
//NullReferenceException:
//Object reference not set to an instance of an object.
string tag2 = sampleEl.Element("Tag2") != null ? sampleEL.Element("Tag2").Value : String.Empty
答案 4 :(得分:1)
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : string.Empty;
答案 5 :(得分:1)
我提出了这种扩展方法。它要求您指定要作为lambda访问的属性,以及当链中的实际值或任何内容为null时使用的默认值:
public static TOut ValueOrDefault<TIn, TOut>(this TIn input, Func<TIn, TOut> projection, TOut defaultValue)
where TOut : class
{
try
{
return projection(input) ?? defaultValue;
}
catch (NullReferenceException)
{
return defaultValue;
}
catch (InvalidOperationException)
{
return defaultValue;
}
}
用法:
var value = topObject.ValueOrDefault(x=>x.ChildObject.AnotherChild.ChildProperty, String.Empty);
如果topObject,ChildObject,AnotherChild或ChildProperty为null,则 value
将为空字符串。如果所有这些都是有效引用,则返回将是ChildProperty实际上的任何内容(它仍然可以是空字符串)。 NullReferenceException的catch处理空引用的子成员的引用。对于可空类型,在访问null可空类型的Value属性时抛出InvalidOperationException。
答案 6 :(得分:1)
C#6.0允许我们使表达更短更简单:
string uniqueIdentifier = myNode.Document?.Element("elem1")?.Element("elem2")?.Attribute("attribute1")?.Value;
答案 7 :(得分:0)
只是为了它的乐趣,这是一个使用LINQ to XML的解决方案
不需要三元运算符,因此您无需两次指定标记的名称:
string tag1 = sampleEl.Elements("Tag1").Select(x => x.Value).FirstOrDefault();
string tag2 = sampleEl.Elements("Tag2").Select(x => x.Value).FirstOrDefault();
如果你想要空字符串而不是?? ""
,如果标签不存在,请添加null
。