Search code examples
c#unity-game-enginepattern-matchingnull-check

Is the "is object expression" null check safe in Unity


My IDE (Rider) keeps suggesting I use

if(s is { })

For null checks, in place of

if(s == null)

After some reaserch it seems like this is becoming the canonical way to do null checks in c#, and it clearly does have some benifits.

However in unity, there are really good reasons why you generally don't want to bypass the overriden equality operator. In other instances where this would happen, like the various null coalescing operators, I get very nice warnings about them not being safe with monobehaviour objects.

The above code generates no such warnings.

My question is, is this actually a safe way to do a null check on monobehaviours or should we still prefer explicit use of ==?


Solution

  • After reading up on @Oliver's comment, and playing around with it on sharplab, I now have a better understanding on why this is safe.

    All of the following

    var s = new P();
        
    if(s is {})
    {
        Foo();
    }
        
    if(s is object)
    {
        Foo();
    }    
        
    if(s is not null)
    {
        Foo();
    }
        
    if(!(s == null))
    {
        Foo();
    }
    

    Produces the exact same

    if (p != null)
    {
        Foo();
    }
    

    When lowered.


    Even more complicated patterns such as

    var nameToMatch = Name.James;
    return s switch
    {
        { firstName: Name.None } => throw new Exception("Person has no name"),
        { } when s.firstName == nameToMatch => true,
        { } when s.firstName != nameToMatch => false,
        null => throw new Exception("Person was null!"),
        _ => throw new ArgumentOutOfRangeException()
    };
    

    Is simply lowered to

    Name name2 = Name.James;
    P p2 = p;
    if (p2 != null)
    {
        if (p2.firstName == Name.None)
        {
            throw new Exception("Person has no name");
        }
        if (p.firstName == name2)
        {
            return true;
        }
        if (p.firstName != name2)
        {
            return false;
        }
        throw new ArgumentOutOfRangeException();
    }
    throw new Exception("Person was null!");
    

    All of which use the safe-for-unity == null checks