Search code examples
c#syntaxnullsafe-navigation-operator

Can a C# Safe Navigation Operator (?.) be used to check if Object is null, as well as property?


This is mainly a syntactic sugar/best-practice question.

Here is a code example in question:

if (_instanceData?.DataSourceType != null && Util.IsEntityBacked(_instanceData.DataSourceType) {// code}

I understand that the safe navigation operator will continue execution if _instanceData is null, but in this case will the first boolean in the conditional be evaluated as expected? Is this going to successfully null check on both _instanceData and DataSourceType?

Another Example:

if (LockAcquired && _instanceData?.ObjInfo != null) {// code}

In this case, it is possible that _instanceData is null, or it is not, but ObjInfo is null. Is it better practice to just old-fashioned null check both object and property, or will this get the job done as expected?

edit: The question is better described as: Is if (obj?.prop != null) equivalent to if (obj != null && obj.prop != null)


Solution

  • The first is equivalent to

    if (_instanceData != null && _instanceData.DataSourceType != null && Util.IsEntityBacked(_instanceData.DataSourceType) {// code}
    

    The second is equivalent to

    if (LockAcquired && _instanceData != null && _instanceData.ObjInfo != null) {// code}
    

    So it will check if _instanceData is null, then check if _instanceData.DataSourceType is null, then the last condition. As you said, this is just syntactical sugar so you don't have to write two != null conditions. The IL code that results is exactly the same, so its a matter of preference whether or not to use the operator.

    It does save a TON of space when accessing deeply nested properties, which is where its most useful

    if(Parent != null)
    {
        if(Parent.Child != null)
        {
            if(Parent.Child.GrandChild != null)
            {
                 Parent.Child.GrandChild.GreatGrandChild.name = "Parent IV";
            }
         }
    }
    

    becomes

    Parent?.Child?.GrandChild?.GreatGrandChild.name = "Parent IV";
    

    Saves a lot of space! Even if you collapsed all the ifs into one statement it still saves loads of keystrokes and screen noise.