Correct use of null-conditional operator in LINQ while reading XML

244 Views Asked by At

I have following XML file that I am parsing using XML serializer.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Projects>
    <Global>
        <Variables>
            <Variable name="GlobalVar1" value="GV1"/>
            <Variable name="GlobalVar2" value="GV2"/>
        </Variables>
    </Global>
    <Project>
        <Variables>
            <Variable name="LocalVar1" value="LV1"/>
            <Variable name="LocalVar2" value="LV2"/>
        </Variables>
    </Project>
</Projects>

I am building a dictionary of variables - name-value pairs. I wrote following LINQ statement which works fine (assume that I don't have duplicate variable names in global and project scope):

Dictionary<String, String> varDict = Projects.Global.Variables.Select(var => new { var.name, var.value })
                .Union(Projects.Project.Variables?.Select(var => new { var.name, var.value }))
                .ToDictionary(var => var.Key, var => var.value);

Now I have a twist - sometimes either the entire <Global> tag will be missing or it won't have the <Variables> tag. Likewise, sometimes <Variables> tag will be missing from the <Project> tag. For example: the XML file will be:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Projects>
    <Project>
        <Variables>
            <Variable name="LocalVar1" value="LV1"/>
            <Variable name="LocalVar2" value="LV2"/>
        </Variables>
    </Project>
</Projects>

I thought using ?. operator (null-conditional), as follows, would help, but when <Global> tag is missing the following LINQ statement returns null (varDict is null):

Dictionary<String, String> varDict = Projects.Global?.Variables?.Select(var => new { var.name, var.value })
                .Union(Projects.Project.Variables?.Select(var => new { var.name, var.value }))
                .ToDictionary(var => var.Key, var => var.value);

What am I doing wrong or what is the solution?

1

There are 1 best solutions below

0
On BEST ANSWER

The ?. operator just avoids throwing a NullReferenceException. It still returns null.

// If Projects.Global is null:
var var1 = Projects.Global?.Variables; // Does not throw an exception, but var1 is null
var var2 = Projects.Global.Variables; // Blows up and throws a NullReferenceException

If you want the .Union() to work when the first part is null, it needs something to work off of. So something like should work (may need some tweaking):

var globalValues = Projects.Global?.Variables?.Select(var => new KeyValuePair<string, string>(var.name, var.value)) 
        ?? new List<KeyValuePair<string, string>>();

Dictionary<String, String> varDict = globalValues
        .Union(Projects.Project.Variables?.Select(var => new KeyValuePair<string, string>(var.name, var.value)))
        .ToDictionary(var => var.Key, var => var.Value);