6

According to Microsoft's documentation, I can compare value types with null, by marking them nullable. This is particularly useful when using null-propagation in nested objects.

However, when comparing specific enums, which I thought were value-types, I can still compare with null, like this:

public class NullColorComparer
{

    public bool CompareNullWithColor()
    {
        // This return false.
        return null == Color.Red;
    }
}

public enum Color
{
    Red,
    Blue
}

Why does this work? Shouldn't compilation fail with a type error?

  • 1
    Your code produces `warning CS0472: The result of the expression is always 'false' since a value of type 'Color' is never equal to 'null' of type 'Color?'` for me. That sums it up quite good I think. – thehennyy Apr 26 '18 at 08:24
  • 2
    Assignment is not possible being value type or when explicitly marked as Nullable enum, but you are doing comparison not assignment – Mrinal Kamboj Apr 26 '18 at 08:24
  • 2
    Btw, that's not enum specific: `int ten = 10; if (null == ten) { }` – Tim Schmelter Apr 26 '18 at 08:27

5 Answers5

6

The enum is casted to a nullable version of it before comparison, so it can and will evaluate. The result is however always the same.

That is why the compiler warns you:

Warning CS0472 The result of the expression is always 'false' since a value of type 'Color' is never equal to 'null' of type 'Color?'

Although the comparison is useless, the compiler doesn't prevent you to perform it. Just like it doesn't prevent your to make a if(false) { }, which is just as useless.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Just a side note: Back in the days of vb6, `if false then...end if` was the only way to create a multi line pseudo comment. Back then, it was very useful. – Zohar Peled Apr 26 '18 at 08:30
  • An interesting observation is that if you paste this line into linqpad: `bool a = null == Color.Red;` you get no warning (using System.Drawing.Color), but with a specific enum in the same linqpad script, you do. – Lasse V. Karlsen Apr 26 '18 at 08:30
  • Definitely strange, i agree. – Lasse V. Karlsen Apr 26 '18 at 08:33
  • @LasseVågsætherKarlsen `Color` is not an enum. It is a struct. – Patrick Hofman Apr 26 '18 at 08:33
  • 1
    Ah, so it's a struct mimicking an enum, didn't know about that distinction, and yes, then it makes sense (that is, it makes sense that the two behave differently, not entirely sure it makes sense that I get no warning but that's entirely different). – Lasse V. Karlsen Apr 26 '18 at 08:34
  • @LasseVågsætherKarlsen You get no warning because the colors are properties, so in theory they could return different values on different calls.. The enum on the other hand has constant values and thus the compiler can determine this. – adjan Apr 26 '18 at 08:42
  • @LasseVågsætherKarlsen, no it's not mimicking an enum, because `Color.Red` would return an object of type `Color`. – 41686d6564 stands w. Palestine Apr 26 '18 at 08:43
  • @AhmedAbdelhameed A struct. And a struct can't be null. – Patrick Hofman Apr 26 '18 at 08:44
  • @Adrian Not entirely. The colors might be properties, but properties returning a struct. And since structs can't be null, the comparison can never be true. However, they failed to provide a check for that. – Patrick Hofman Apr 26 '18 at 08:44
  • @LasseVågsætherKarlsen The funny thing is it does fail on `Color red = new Color(); var b = red == null;` (in this case it even is an error!) – Patrick Hofman Apr 26 '18 at 08:46
  • @LasseVågsætherKarlsen only primitive structs (enum, int etc) generate this warning (and `Color` is custom struct). You can read about reasons (basically - backward compatibility) here: https://github.com/dotnet/roslyn/issues/18975. There you can also read that using `strict` you can make compiler generate this warning for all structs. – Evk Apr 26 '18 at 08:56
  • @PatrickHofman Yes you're right. Actually, you can't even use the `==` operator unless its overloaded in the struct itself... So in theory you could define an operator that compares to a reference type like `static bool operator == (Object left, MyStruct right)` and then you could compare it with `null`, and have it evaluate to `true`. However, the compiler should know whether such an overload exists (in case of `System.Drawing.Color` it doesn't) – adjan Apr 26 '18 at 09:01
1

The null side of your comparison is treated as a Nullable<Program.Color> and it will compile, because you can compare a Nullable<WhatEver> to a WhatEver.

It will however, issue a warning:

Warning CS0472 The result of the expression is always 'false' since a value of type 'Program.Color' is never equal to 'null' of type 'Program.Color?'

nvoigt
  • 75,013
  • 26
  • 93
  • 142
0

C# compiler doesn't prevent comparing. But you get a warning: "The result of the expression is always 'false' since the value of type 'Color' is never equal to 'null' of type 'Color?'". It lets you compare, but says that it always will be false. This is true for any value type. You can even compare an Int32 value with null, you will get the same result. No need for compile time error'

0

Even though a value type can never be null, you can still compare value types to null and it will always result in false.

Some tools like ReSharper can detect that and might actually warn you that it's a useless comparison.

Tom Pažourek
  • 9,582
  • 8
  • 66
  • 107
0

Definitely, Based on your code you always will get false because you are comparing a static instance of enum with a null value.

Your comparison will be meaningful is some case like this:

public enum TestEnum
    {
        Item1,
        Item2
    }

...

TestEnum? t = null; 
return  t== null;

...

Mohammad Nikravesh
  • 947
  • 1
  • 8
  • 27