lc.
lc.

Reputation: 116438

What is the difference between Nullable<T>.HasValue or Nullable<T> != null?

I always used Nullable<>.HasValue because I liked the semantics. However, recently I was working on someone else's existing codebase where they used Nullable<> != null exclusively instead.

Is there a reason to use one over the other, or is it purely preference?

  1. int? a;
    if (a.HasValue)
        // ...
    

vs.

  1. int? b;
    if (b != null)
        // ...
    

Upvotes: 543

Views: 145572

Answers (5)

Carter Medlin
Carter Medlin

Reputation: 12465

In VB.Net, do NOT use IsNot Nothing when you can use .HasValue. I just solved an "Operation could destabilize the runtime" Medium trust error by replacing IsNot Nothing with .HasValue in one spot. I don't really understand why, but something is happening differently in the compiler. I would assume that != null in C# may have the same issue.

Upvotes: 16

Rex M
Rex M

Reputation: 144112

The compiler replaces null comparisons with a call to HasValue, so there is no real difference. Just do whichever is more readable/makes more sense to you and your colleagues.

Upvotes: 596

yan yankelevich
yan yankelevich

Reputation: 935

If you use linq and want to keep your code short, I recommand to always use !=null

And this is why:

Let imagine we have some class Foo with a nullable double variable SomeDouble

public class Foo
{
    public double? SomeDouble;
    //some other properties
}   

If somewhere in our code we want to get all Foo with a non null SomeDouble values from a collection of Foo (assuming some foos in the collection can be null too), we end up with at least three way to write our function (if we use C# 6) :

public IEnumerable<Foo> GetNonNullFoosWithSomeDoubleValues(IEnumerable<Foo> foos)
{
     return foos.Where(foo => foo?.SomeDouble != null);
     return foos.Where(foo=>foo?.SomeDouble.HasValue); // compile time error
     return foos.Where(foo=>foo?.SomeDouble.HasValue == true); 
     return foos.Where(foo=>foo != null && foo.SomeDouble.HasValue); //if we don't use C#6
}

And in this kind of situation I recommand to always go for the shorter one

Upvotes: 0

cbp
cbp

Reputation: 25628

I prefer (a != null) so that the syntax matches reference types.

Upvotes: 60

Perrin Larson
Perrin Larson

Reputation: 562

I did some research on this by using different methods to assign values to a nullable int. Here is what happened when I did various things. Should clarify what's going on. Keep in mind: Nullable<something> or the shorthand something? is a struct for which the compiler seems to be doing a lot of work to let us use with null as if it were a class.
As you'll see below, SomeNullable == null and SomeNullable.HasValue will always return an expected true or false. Although not demonstrated below, SomeNullable == 3 is valid too (assuming SomeNullable is an int?).
While SomeNullable.Value gets us a runtime error if we assigned null to SomeNullable. This is in fact the only case where nullables could cause us a problem, thanks to a combination of overloaded operators, overloaded object.Equals(obj) method, and compiler optimization and monkey business.

Here is a description of some code I ran, and what output it produced in labels:

int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")

Ok, lets try the next initialization method:

int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")

All the same as before. Keep in mind that initializing with int? val = new int?(null);, with null passed to the constructor, would have produced a COMPILE time error, since the nullable object's VALUE is NOT nullable. It is only the wrapper object itself that can equal null.

Likewise, we would get a compile time error from:

int? val = new int?();
val.Value = null;

not to mention that val.Value is a read-only property anyway, meaning we can't even use something like:

val.Value = 3;

but again, polymorphous overloaded implicit conversion operators let us do:

val = 3;

No need to worry about polysomthing whatchamacallits though, so long as it works right? :)

Upvotes: 23

Related Questions