tags:

views:

129

answers:

2

The docs for Object.Equals says that implementors must return false if the parameter is a null reference.

In my class, I'm overriding Equals to check for value equality. I have a member variable which is similar to the Nullable (T) structure. My initial inclination is to return True when I'm passed a null reference and my structure's HasValue property is False.

Is it ever acceptable to return True when the parameter to Equals is a null reference?

EDIT For illustration:

class ExampleClass {

    SomeValueType? x;

    bool Equals(object other) {
        if (other == null) return false; // <-- returns a different value than x.Equals
        return x.Equals(other); 
    }
}
+6  A: 

Nullable<T>.Equals(object) is the following:

public override bool Equals(object other)
{
    if (!this.HasValue)
    {
        return (other == null);
    }
    if (other == null)
    {
        return false;
    }
    return this.value.Equals(other);
}

So the answer to your question is yes in the case of a struct (value type) with nullable semantics. If your type is a class (reference type), the answer is definitely no.

280Z28
Well, my class is deferring to my struct's `Equals`. It just seems unintuitive that it wouldn't defer in the special case of null references
Ken Browning
From the limited information I have now (including your example), your design seems unintuitive. I hold that for a reference type, `Equals` should *always* return `false` when `obj==null`. What exactly are you trying to do here? Why not make `x` a `SomeValueType` instead of `SomeValueType?`?
280Z28
It's a wrapper around Nullable(T) which allows inheritors to implement a TryParseValueFromString method.
Ken Browning
@Ken: Follow the well-established .NET framework pattern and place a static `bool TryParse(string, out SomeType)` method in your struct/class. There cannot be confusion about the method signature (name, return value, parameters) because there is no other acceptable way to do this.
280Z28
Well, I do follow that pattern except its not static. It's a member function which will typically call DateTime/Int32/Etc.TryParse(). I'm not sure if you're familiar with `SmartDate` which is a class in CSLA. It's goal is to be the storage member for a property which a business object exposes as string but is stored in the database as a DateTime. This is the same concept. My SmartDate would subclass from the class in question and implement TryParseValue by calling DateTime.TryParse.
Ken Browning
The reason I'm not basing my implementation on SmartDate is because it's implemented as a mutable struct.
Ken Browning
I guess I'm not seeing why you couldn't either 1) since it's clearly a date, expose the object as a `DateTimeOffset` (non-nullable) or `DateTimeOffset?` (nullable) or 2) expose a `string` property backed by a `DateTimeOffset`/`DateTimeOffset?` private member and call `ToString` in the getter and `Parse` in the setter when the value is not `null`.
280Z28
I get it now. Thanks for your help. I won't store my struct inside my "Smart" classes.
Ken Browning
+1  A: 

Actually it is not. The equals method cannot return true when two objects are null.

Why?

Well when you define

AnObject obj;

obj is a reference to an object (I am talking for Java but this must be a OO concept)

Object.Equals method takes a parameter which must be an object however null is not an object.

so null.Equals(null) is not an acceptable approach for OO.

Edit:

That's why == operator differs from obj.Equals method. null == null returns true without any headache.

Edit2: It seems that .Net has an inconsistency about Equals method which may be subject to another topic.

int? a = null;
a.Equals(null); // returns true without any problem.

but:

Nullable<T>.Equals method is defined like this:

Nullable<T>.Equals(object obj):bool

Indicates whether the current Nullable value is equal to a specified object

Since null is not an object, either the documentation or the implementation is not correct.

JCasso
More specifically, this is the difference between the static method `Object.Equals(Object,Object)` and the virtual member method `Object.Equals(Object)`. Your answer doesn't account for the fact that according to the standard (ECMA-335) the special value type `Nullable<T>` boxes to `null` whenever `HasValue` is false.
280Z28
@jcasso: The standard, ECMA-335, specifically gives special semantics to the value type `System.Nullable<T>`, which boxes to the object reference `null` whenever `HasValue` is `false`. The only other option would be to make `Nullable<T>` a reference type that could actually be set to a `null` reference, but that would have a significant (negative) impact on performance because it would effectively be the same as boxing/unboxing the underlying type.
280Z28
@280Z28 It seems that Nullable<T>.equals(object) method does a different job here. It overrides System.Object.Equals method. Does not throw exception if the HasValue property is false... As I mentioned above I was talking for Java but what we talk here is not about just a language, it is about Object Oriented Programming.And for me I still insist that this is a very bad approach. Equals mehtod must compare to objects, not the references of objects.
JCasso
And also "an object may or may not be equal to an object if it does not have a value" algorithm? Congratulations to the inventor.
JCasso