简体   繁体   English

访问可能存在或不存在的子元素时,避免使用对象空引用异常

[英]Avoid object null reference exception when accessing sub-elements that may or may not exist

I have: An XML with some elements. 我有:带有一些元素的XML。 A sub-element that may or may not be defined inside this XML. 可以在此XML中定义的子元素,也可以不在此XML中定义。 Need to extract the value of the sub-element when it does exist. 需要在子元素存在时提取子元素的值。

How do I get the value without throwing object-reference errors? 如何在不抛出对象引用错误的情况下获取值?

For example: 例如:

 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;

You can use the null-coalescing-operator for a shortcut: 您可以使用null-coalescing-operator作为快捷方式:

 string tag1= (string)sampleEl.Element("Tag1") ?? string.Empty;

This also uses the fact that LINQ to XML allows the cast operation to get the value of the element (in this case cast to string), but returns null if the element does not exist. 这也使用LINQ to XML允许转换操作获取元素的值(在这种情况下转换为字符串),但如果元素不存在则返回null

You'll need to check for null in order to prevent them. 您需要检查null以防止它们。 Given the repeated pattern you're using I would just factor this off into an extension method. 鉴于您正在使用的重复模式,我只会将其分解为扩展方法。

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;
}

Now your above code can be replaced with the following 现在您的上述代码可以替换为以下代码

string tag1 = sampleEl.GetElementValue("Tag1");
string tag2 = sampleEl.GetElementValue("Tag2");

C#三元运算符非常适合这个:

string tag2 = sampleEl.Element("Tag2") == null ? "" : sampleEl.Element("Tag2").Value;

First you should check if the document is null, remember you are accessing the .Value and this will throw a null reference exception so before you apply .value do a test: 首先,你应该检查文档是否为null,记住你正在访问.Value,这将抛出一个空引用异常,所以在你申请之前.value做一个测试:

if (sampleEl != null)
  //now apply .value

Or ternary: 或者三元:

string tag2 = sampleEl.Element("Tag2") != null ? sampleEL.Element("Tag2").Value : String.Empty

Your code then becomes: 然后你的代码变成:

 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

C#6.0允许我们使表达式更短更简单:

 string uniqueIdentifier = myNode.Document?.Element("elem1")?.Element("elem2")?.Attribute("attribute1")?.Value;
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : string.Empty;

I came up with this extension method. 我提出了这种扩展方法。 It requires you to specify the property to access as a lambda, and a default value to use if the actual value or anything up the chain is null: 它要求您指定要作为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;
        }
    }

Usage: 用法:

var value = topObject.ValueOrDefault(x=>x.ChildObject.AnotherChild.ChildProperty, String.Empty);

value will be the empty string if topObject, ChildObject, AnotherChild, or ChildProperty are null. 如果topObject,ChildObject,AnotherChild或ChildProperty为null,则value将为空字符串。 If all of those are valid references, the return will be whatever ChildProperty actually is (which could still be the empty string). 如果所有这些都是有效引用,则返回将是ChildProperty实际上的任何内容(它仍然可以是空字符串)。 The catch for the NullReferenceException handles references of child members of a null reference. NullReferenceException的catch处理空引用的子成员的引用。 For nullable types, InvalidOperationException is thrown when accessing the Value property of a null nullable type. 对于可空类型,在访问null可空类型的Value属性时抛出InvalidOperationException。

Just for the fun of it, here's a solution using LINQ to XML which 只是为了它的乐趣,这是一个使用LINQ to XML的解决方案

  • requires only one statement and 只需要一份陈述和
  • does not need the ternary operator, so you don't need to specify the name of the tag twice: 不需要三元运算符,因此您不需要两次指定标记的名称:

     string tag1 = sampleEl.Elements("Tag1").Select(x => x.Value).FirstOrDefault(); string tag2 = sampleEl.Elements("Tag2").Select(x => x.Value).FirstOrDefault(); 

Add ?? "" 添加?? "" ?? "" if you want the empty string instead of null if the tag does not exist. ?? ""如果你想要空字符串而不是null如果标签不存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 访问可能存在或可能不存在的子元素时,请避免对象空引用异常(JSON) - Avoid object null reference exception when accessing sub-elements that may or may not exist (JSON) 选择XML中可能存在或不存在的子元素列表 - Selecting a list of sub elements in XML that may or may not exist 节点可能存在或不存在时的XML解析 - XML parsing when node may or may not exist 为什么我可以在它可能不可为空或可能不是对象的情况下测试null的泛型? - Why can I test a generic for null when it may not be nullable or may not be an object? 删除数据库中可能存在或可能不存在的实体框架对象 - Deleting an Entity Framework object that may or may not already exist in the database LINQ:当对象可能为null时,一种更好的选择属性的方法吗? - LINQ: A better way to select a property when the object may be null? C# 检查和调用可能存在或不存在的 object 属性 - C# Checking and calling object properties that may, or may not exist 访问OnClick中的属性时出现Null Reference异常 - Null Reference exception when accessing property in OnClick 使用Autofac访问单例时出现Null Reference异常 - Null Reference exception when accessing a singleton with Autofac 在 C# 中使用反射动态访问 object 的属性时避免 null 引用警告 - Avoid null reference warnings when dynamically accessing properties of object using reflection in C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM