0

I use unity, the I try following code:

    class C
    {

    }

    void m()
    {
        var c = GetComponent<Collider>();
        if (c)
        {

        }

        var c2 = new C();
        if (c2)
        {

        }
    }

the Rider syntax check show: enter image description here

if (c) syntax is correct and if (c2) raise syntax err, I hope if (c2) syntax right, how should i modify my class C

chikadance
  • 3,591
  • 4
  • 41
  • 73
  • 1
    What does `GetComponent()` return? – phuzi Apr 19 '18 at 14:41
  • 1
    Assuming it returns `Collider`, presumably there's an implicit conversion from `Collider` to `bool`. That's not very idiomatic in general though - I would not try to emulate it in your own class. – Jon Skeet Apr 19 '18 at 14:42
  • `if (c)` will only work if `c` is a boolean value, or can be implicitly cast to a boolean value. –  Apr 19 '18 at 14:42
  • @DaisyShipton Yep, `Collider` has an implicit conversion to `bool`: https://docs.unity3d.com/ScriptReference/Collider.html (search page for "does the object exist"). –  Apr 19 '18 at 14:44

4 Answers4

4

First off: the design of the unity library here is bad C# API design and you should not attempt to replicate it. It is not idiomatic in C# to check objects for nullity with if(c). You should always check for nullity with if (c != null) and you should design your objects to be checked for null like that.

The only time that you would typically enable if(c) style checking is if the object logically represents a Boolean without actually being a bool. For example, suppose you have a type SecurityCheck that represents whether a user passed a security check or not; you might have more information in an instance than just a bool, but you might want to be able to use it in contexts where a bool is expected.

In that case there are two ways to do it.

  • If an instance can be converted to bool then you write a user-defined implicit conversion to bool.
  • If you want to preserve the content of the instance in custom implementations of & and | then you should provide custom implementations of operators |, &, true and false. If you do so then if, while, and so on, will use operator true to determine if the condition is met.

But again: do not emulate the design of Unity here. Do not make conversions to bool that just check nullity. That's not the way we check for nullity in C#. If you want to check for null you should write a null check.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
1

The check you have shown for c2 will not work in C# (as opposed to, for example, Javascript).

Instead, you have to explicitly test against null. Or you can use the null-conditional operators.

All of the following variants will prevent NullReferenceException when calling DoSomething().

Check for null and throw:

if (c2 == null) {
    throw new ArgumentNullException(nameof(c2));
}
c2.DoSomething();

Check for not null and do work:

if (c2 != null) {
    c2.DoSomething();
}

Use null-conditional operator:

c2?.DoSomething(); // will do nothing if c2 is null
Georg Patscheider
  • 9,357
  • 1
  • 26
  • 36
1

I would check the null state of c2 by simply using:

if (c2 != null)

This is standard, clear, and concise.

We often like to make our code ever more concise, hence trying to simplify the logic down to if (c2), but it's not clear that the object returned from the C() constructor can be implicitly converted to a bool. Even if a C object could be implicitly converted to a bool, that would be uncommon, and so programmers who come along after you might wonder why/how you're checking whether the object is null that way.

To take this case even further, I would check for the null state of c in the same way instead of relying on GetComponent<Collider>() to return a bool. Often, clarity is preferred over brevity.

Jake Reece
  • 1,140
  • 1
  • 12
  • 23
  • "it's not clear that the C() constructor returns a bool" Constructors don't return anything at all. They construct objects. Whether that constructed object can be implicitly converted to a bool is not touched on in your answer. –  Apr 19 '18 at 14:50
  • 2
    The fact that the code compiles at all makes it clear that there's an implicit conversion to boolean. What's not clear is what that boolean represents. It could mean whether or not it has a value, or any number of other things. That's the real danger. – Servy Apr 19 '18 at 14:53
  • @Amy True; thank you. I've updated the answer with more accurate wording regarding the constructor. – Jake Reece Apr 19 '18 at 15:03
1

Readability should always be a higher priority so doing checks like if(c != null) or if(c == null) aren't a bad thing(They are a good thing), it shows that you meant to enter that function specifically for those circumstance were if(!c) can sometimes be misinterpreted because someone misses ! but to answer your question you can change your Class C to this:

class C
{
    public static implicit operator bool(C obj) 
    {
        return obj != null; 
    }
}

Be aware though, that just because you can if(collider) an object does not necessarily mean that implicit conversion means it isn't null it can mean something else. In the example code I posted it does check if the object isn't null.

AresCaelum
  • 1,558
  • 1
  • 13
  • 18