Using XDocument.Descendants with a coalesce operator ?? and nullable types

Compiler: Visual Studio 2019
Framework: .Net 2.1

Given a XML file like this:

            <AdditionalInfoItem key="{4567B566-A0A2-4214-B7E7-814FE179CDFC}" value="ScanItDental"/>
            <AdditionalInfoItem key="GlobalOrderID" value="EDC531BE6A0D4DC5BFEA0C6081D9F26B"/>
            <AdditionalInfoItem key="CreatedIn" value=""/>

I need to get AdditionalInfoItem only for certain key values.

To avoid null errors I’m trying to use nullable types and coalesce operator ??

var additionalOrderInfo = document.Descendants(ns + "AdditionalOrderInfo").First();
var value = additionalOrderInfo.Descendants(ns + "AdditionalInfoItem")?.Where(el => el.Attribute("key").Value == "SomeKey")?.First()?.Attribute("value")?.Value ?? "";

But if key doesn’t exists it returns:

Sequence contains no elements.

I’ve ended using a foreach loop in this way:

var additionalOrderInfo = document.Descendants(ns + "AdditionalOrderInfo").First();
foreach (var item in additionalOrderInfo.Descendants(ns + "AdditionalInfoItem"))
    switch (item.Attribute("key").Value)
        case "SomeKey1":
            Order.SomeKey1 = item.Attribute("value").Value;
        case "SomeKey2":
            Order.SomeKey2 = item.Attribute("value").Value;

Is there a way to avoid the foreach loop and read the value using a single line of code?

>Solution :

Try use FirstOrDefault instead of First only after Where selector:

var value = additionalOrderInfo.Descendants(ns + "AdditionalInfoItem")?
                               .Where(el => el.Attribute("key").Value == "SomeKey")?
                               .FirstOrDefault()? // <--- Here
                               .Attribute("value")?.Value ?? "";

If Where(el => el?.Attribute("key")?.Value == "SomeKey") return 0 elements, you getting Sequence contains no elements exception, so you can’t get First element of it. FirstOrDefault returns null instead, so next nullcheck ? goes forward.

Leave a Reply