簡體   English   中英

訪問可能存在或不存在的子元素時,避免使用對象空引用異常

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

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

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

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

這也使用LINQ to XML允許轉換操作獲取元素的值(在這種情況下轉換為字符串),但如果元素不存在則返回null

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

C#三元運算符非常適合這個:

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

首先,你應該檢查文檔是否為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

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;

我提出了這種擴展方法。 它要求您指定要作為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。

只是為了它的樂趣,這是一個使用LINQ to XML的解決方案

  • 只需要一份陳述和
  • 不需要三元運算符,因此您不需要兩次指定標記的名稱:

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

添加?? "" ?? ""如果你想要空字符串而不是null如果標簽不存在。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM