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

发布于 2024-10-21 07:34:17 字数 864 浏览 2 评论 0原文

我有: 包含一些元素的 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;

I have:
An XML with some elements.
A sub-element that may or may not be defined inside this 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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

渔村楼浪 2024-10-28 07:34:18

您需要检查 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");

You'll need to check for null in order to prevent them. 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");
心不设防 2024-10-28 07:34:18

C# 三元运算符非常适合此操作:

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

The C# ternary operator is pretty good for this:

string tag2 = sampleEl.Element("Tag2") == null ? "" : sampleEl.Element("Tag2").Value;
无远思近则忧 2024-10-28 07:34:18

首先,您应该检查文档是否为空,记住您正在访问 .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

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:

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
终陌 2024-10-28 07:34:18
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : string.Empty;
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : string.Empty;
泪眸﹌ 2024-10-28 07:34:18

我想出了这个扩展方法。它要求您指定要以 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,value 将是空字符串、AnotherChild 或 ChildProperty 为 null。如果所有这些都是有效的引用,则返回的值将是 ChildProperty 实际是什么(仍然可能是空字符串)。 NullReferenceException 的捕获处理空引用的子成员的引用。对于可为 null 的类型,当访问可为 null 的类型的 Value 属性时,会引发 InvalidOperationException。

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:

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. If all of those are valid references, the return will be whatever ChildProperty actually is (which could still be the empty string). The catch for the NullReferenceException handles references of child members of a null reference. For nullable types, InvalidOperationException is thrown when accessing the Value property of a null nullable type.

梦中楼上月下 2024-10-28 07:34:18

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

 string uniqueIdentifier = myNode.Document?.Element("elem1")?.Element("elem2")?.Attribute("attribute1")?.Value;

C# 6.0 allows us to make the expression shorter and simpler:

 string uniqueIdentifier = myNode.Document?.Element("elem1")?.Element("elem2")?.Attribute("attribute1")?.Value;
飘然心甜 2024-10-28 07:34:18

只是为了好玩,这里有一个使用 LINQ to XML 的解决方案,它只

  • 需要一个语句,并且
  • 不需要三元运算符,因此您不需要两次指定标记名称:

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

添加??如果您想要空字符串而不是 null(如果标签不存在),则为“”

Just for the fun of it, here's a solution using LINQ to XML which

  • 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.

吖咩 2024-10-28 07:34:17

您可以使用null-coalescing-operator 作为快捷方式:

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

这也利用了以下事实:LINQ to XML 允许强制转换操作获取元素的值(在本例中强制转换为字符串),但如果元素不存在则返回 null存在。

You can use the null-coalescing-operator for a shortcut:

 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文