tags:

views:

103

answers:

2

I am talking about C# language here.

Definition of Object.Equals(Object) method in msdn is:

Determines whether the specified Object is equal to the current Object.

If two objects are equal it returns true, however if they are null it returns false:

x.Equals(a null reference (Nothing in Visual Basic)) returns false.

Why? Because null is not an object.

A NullReferenceException is thrown if the object paremeter is null.

and also we have this:

x.Equals(y) returns the same value as y.Equals(x).

No problem at all till here. It is very similar to Java. But C# also provides a System.Nullable struct for non-nullable types. As far as I know, a struct is an object. It inherits Object.Equals method.

If I have a struct like this:

struct Car
    {
        public string Make;
        public string Model;
        public uint Year;

        public Car(string make, string model, uint year)
        {
            Make = make;
            Model = model;
            Year = year;
        }
    }

And create four instances:

Car car1 = new Car("make", "model", 2009);
Car car2 = new Car("make", "model", 2009);
Car car3 = new Car("make", "model", 2008);

car1.Equals(car2); // will return true
car1.Equals(car3); // will return false;

And as far as I know we can't set a struct to a null value. But System.Nullable is a struct and we can do compile this without any errors:

int? i = null;

(I hope that someone can explain this also. Is it a struct or something else?)

My real question is:

i.Equals(null); // returns true!

(Normally x.Equals(y) = y.Equals(x) Of course null.Equals(i) is not valid here... )

Obviously Object.Equals method is overridden here. Maybe it is documented and this is specified. But is this approach correct/nice ? If so what is the difference between == and Equals method for Nullable values?

+9  A: 

I think your confusion is rooted in the following line

i? = null;

This does not actually create a null value variable. It's essentially syntatic sugar for the following

Nullable<int> i = new Nullable<int>();

The resulting property HasValue on i will have the value false. It is not null but instead a value type with empty values. Or just an empty nullable. IMHO, the best way to think of this is that null is convertible to an empty Nullable<T> for any given T.

Knowing that it makes the line i.Equals(null) a bit easier to understand. It's syntatic sugar for the following

Nullable<int> i = new Nullable<int>();
i.Equals(null);

The type Nullable<T> only overrides Equals(object). The implementation of this method though considers a null value to be Equal to an empty nullable value. So it's behaving correctly.

JaredPar
But, whatever it does in the background we call i.Equals(null) and it returns true when i is null. It should return false for any other object.
JCasso
@jcasso, Nullable's in general are ... weird and often behave in unexpected ways. Part of the confusion is that i can't ever be null because it is in fact a value type. It's better to think of it as an empty nullable.
JaredPar
At least you accepted that it is weird :) I thought that I was the only one.
JCasso
Note that the _static_ method `Object.Equals(null, null)` will return true, so it's well-established that `null` is equal to `null`. The only reason why you get a `NullReferenceException` when you call `null.Equals(y)` is because semantics of instance method calls on reference types demand that; it has nothing to do with semantics of `Equals` itself. Since `Nullable<T>` is not a reference type, this doesn't apply.
Pavel Minaev
Like I pointed out in the other post, i.Equals(null) is not calling Object.Equals. It is a virtual call constrained to the Nullable<int> type.
James Deville
+2  A: 

To answer your side question, Nullable is a struct with a T: Struct constraint. So, even though int? i = null; is null, i is an instance of the Nullable struct.

James Deville
A struct may take null value? Can you define Car car4 = null; ?
JCasso
Struct cannot have a `null` value as far as CLR is concerned. In C#, when you write `int? x = null`, you are actually writing `int? x = new int?()`. There's no real `null` involved there at all.
Pavel Minaev
no. but when you do int? i = <<some legal value>>, the CLR puts that legal value into the value property of i. Also, just FYI, Nullable overrides the Equals method
James Deville
Also, looking at the IL underneath a call to int? i = null; The CLR loads the address that it has assigned to the variable, then initializes an empty Nullable<int> object (with null fields) into that address.
James Deville
@pavel: much more concise way to say what i was trying to say in my second comment :)
James Deville