The "is" keyword: there a difference in these methods? - c#

Not really sure about the is keyword, but I think these two are the same. Can anyone confirm this?
public bool Equals(Object obj)
{
if (obj == null) return false;
MyType t = (MyType)obj;
if (t == null) return false;
return true;
}
and the other is...
public bool Equals(Object obj)
{
return obj is MyType;
}

No, they are definitely not equal. The cast to (MyType) will throw InvalidCastException immediately if obj isn't an instance of MyType. The expression will not evaluate to null if the cast fails. as operator exhibits the behavior you are expecting from that cast. My answer to another question discusses this in a bit more detail.

They are not the same. If obj is not MyType, the first version throws an exception, the second version returns false.
And this implementation of Equals() is quite strange. Are you sure you want to consider all instances of MyType as equal?

In the first method, you risk the cast failing and throwing an exception. I think you might be mixed up with the as keyword, which returns null if the cast fails instead. Once that's fixed, the methods would be roughly equivalent:
public bool Equals(Object obj)
{
return (obj as MyType) != null;
}
But the latter is more concise and clear anyway.

Not the same, the 1st version bombs with an InvalidCastException if an object of an unrelated type is passed.
Equals() is supposed to test for value equality, not type equality.

An is expression evaluates to true if both of the following conditions
are met:
expression is not null.
expression can be cast to type.
That is, a cast expression of the form (type)(expression) will complete without
throwing an exception. For more information, see 7.6.6 Cast
expressions. A compile-time warning will be issued if the expression
expression is type is known to always be true or always be false.
From MSDN
The methods are not the same. If obj is not of MyType it will throw an exception while is will not, it will return false.

Related

How does overloading the equality operator == really work?

I have this piece of code in MyClass:
public static bool operator ==(MyClass lhs, MyClass rhs)
{
if (lhs == null || rhs == null)
return false;
// Other operations to check for equality
}
Going by the first line in the code, I'm comparing lhs and rhs to null. I'm not sure but I suppose that comparison itself will invoke the overload function again. And then we het to that line again, it invokes itself and so on. Sort of an infinite recursion.
But we all know that does not take place. This implies, in my opinion, that comparing with null does not invoke the equality overload. So what really occurs? How does comparing with null work?
EDIT
I stand corrected. It does call the == operator recursively (at least in LinqPad 4.5) rather than binding to object.==. There are three ways to fix this:
Overload Equals instead if you really want value equality semantics.
Cast lhs and rhs to object
Use Object.ReferenceEquals as the MSDN guidelines recommend
I suppose that comparison itself will invoke the overload function again
No - null is not a MyClass so the call uses the default meaning of == which is reference equality.
Also note that the guidelines for overloading == state that it should only be overloaded for immutable types, since the expected behavior for == is reference equality which is what happens by default. Equals implies "value equality" semantics.
In addition to D Stanley answer. To avoid such kind of surprizes (Object operator == is called), use Object.ReferenceEquals when implementing ==:
public static bool operator ==(MyClass lhs, MyClass rhs)
{
// lhs and rhs are the same instance (both are null included)
if (Object.ReferenceEquals(lhs, rhs))
return true;
else if (Object.ReferenceEquals(lhs, null) || Object.ReferenceEquals(rhs, null))
return false;
// From here we have different instances, none of them is null
// Other operations to check for equality
}

Check for null in == override

In the following C# snippet I override the == method. _type is a number of type short. So I'm actually saying that two WorkUnitTypes are the same when those two shorts are the same.
public static bool operator ==(WorkUnitType type1, WorkUnitType type2)
{
if (type1 == null || type2 == null)
return false;
return type1._type == type2._type;
}
Because R# warns me, and it is totally clear why, that type1/type2 could potentially be null I'm trying to catch that with the if statement above.
Now I'm getting a StackOverflowException which makes totally sense because I'm actually calling the override.
Question: How do I write this method "correct". How can I catch the case that type1 or type2 can be null?
My best guess: Maybe I'm just misusing == here and checking for equality should be done with the Equals override. But still I think the problem exists. So where is my error in reasoning?
You're looking for the ReferenceEquals() function, which will compare directly, bypassing your operator overload.
In addition to what SLaks said, you likely also want to return true if both are equal to null. So, like this:
public static bool operator ==(WorkUnitType type1, WorkUnitType type2)
{
if (ReferenceEquals(type1, null))
return ReferenceEquals(type2, null);
if (ReferenceEquals(type2, null))
return false;
return type1._type == type2._type;
}
For completeness' sake: you can also cast the two arguments to object. This will use the implementation as defined in object and not your custom one.
In code:
if ((object) type1 == null || (object) type2 == null)

Result of calling IEquatable<T>.Equals(T obj) when this == null and obj == null?

What should IEquatable<T>.Equals(T obj) do when this == null and obj == null?
1) This code is generated by F# compiler when implementing IEquatable<T>. You can see that it returns true when both objects are null:
public sealed override bool Equals(T obj)
{
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
// Code when both this and obj are not null.
}
2) Similar code can be found in the question "in IEquatable implementation is reference check necessary" or in the question "Is there a complete IEquatable implementation reference?". This code returns false when both objects are null.
public sealed override bool Equals(T obj)
{
if (obj == null)
{
return false;
}
// Code when obj is not null.
}
3) The last option is to say that the behaviour of the method is not defined when this == null.
leppie is right. Just to elaborate on his answer (and confirm his suspicion that F# doesn't guarantee this != null): discriminated unions may be marked with the attribute [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] allowing cases to be represented by the value null. Option<'T> is such a type. The None case is represented by null at run-time. (None : option<int>).Equals(None) is syntactically valid. Here's a fun example:
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type Maybe<'T> =
| Just of 'T
| Nothing
[<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
member this.ThisIsNull() = match this with Nothing -> true | _ -> false
Decompiling ThisIsNull with Reflector shows
public bool ThisIsNull()
{
return (this == null);
}
And the result:
Nothing.ThisIsNull() //true
The reason F# does this (I suspect) to optimize empty lists as null.
By adding this check, it allows one to call an instance method on a null instance without any problems.
See my blog post from a while back.
In C#, this is irrelevant.
To answer the question:
It should return true as both instances are null and deemed equal.
If this is null, the code can't be called, so that case needn't be considered (in C# anyway, there are cases where languages allow a null object to have a method dereferenced though obviously if it internally examines any of its non-existent fields it will error. Consider:
return x.Equals(y);
If x is null, we don't even get to call into Equals for the null check to count.
Hence we need only consider:
public bool Equals(T obj)
{
if(obj == null)
return false;
//logic defining equality here.
}
Where the possibility of both objects being null does come up, is when we are examining them from a static == operator override or from an IEqualityComparer<T> implementation:
public bool Equals(T x, T y)
{
if(x == null)
return y == null;
if(y == null)
return false;
//logic defining equality here.
}
Note that a useful shortcut here if equality can be lengthy to determine (e.g. comparing long strings), then we may take advantage of the fact that identity entails equality - that is something is always equal to itself, even Ayn Rand could figure that out ;) There are also algorithms that make comparing an item with itself quite common, making this shortcut well worth including. In this case the identity comparison already includes the check for both being null, so we leave it out again:
public bool Equals(T x, T y)
{
if(ReferenceEquals(x, y))
return true;
if(x == null || y == null)
return false;
//logic defining equality here.
}
For most methods I assume undefined behavior when called with this==null. That's because most programmers write their code under the assumption that this!=null, which is guaranteed by the C# specification if the calling code is written in C#.
That's why every sane caller of x.Equals(y) should either know for sure that that x is not null, or add a manual null check.
In most cases I wouldn't call Equals directly at all, but instead use EqualityComparer<T>.Default.
I would definitelly go with option 1:
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
null object always equals null object.
Sample code is in the MSDN: http://msdn.microsoft.com/en-us/library/ms131190.aspx?ppud=4
If this==null you will get a runtime exception calling Equals() on that object.

Cast to object before null check in overriding Equals [duplicate]

This question already has answers here:
In the msdn guidance on Equals override, why the cast to object in the null check?
(3 answers)
Closed 5 years ago.
Just reading the msdn article on overriding equality operators here
The following snippet confuses me...
// If parameter cannot be cast to Point return false.
TwoDPoint p = obj as TwoDPoint;
if ((System.Object)p == null) // <-- wtf?
{
return false;
}
Why is there a cast to Object here to perform the null comparison?
Operators apply through static analysis (and overloads), not virtual methods (overrides). With the cast, it is doing a reference equality check. Without the cast, it can run the TwoDPoint operator. I guess this is to avoid problems when an operator is added.
Personally, though, I'd do a reference check explicitly with ReferenceEquals.
No! if you don't do that, the runtime will start a recursive call to the equality operator you are just in which results in infinite recursion and, consequently, a stack overflow.
To force it to use the Equals method of Object rather than its own overloaded version... just a guess...
This is not useless. Without that cast the == operator being overloaded would be called recursively...
the below is the line that does the cast
TwoDPoint p = obj as TwoDPoint
the difference with the "normal" cast is that using "As" it doesn't raise an exception if the object is not "castable". In this case if "p" is not a TwoDPoint Type is not gonna raise an exception (cast not valid) but return null.
if ((System.Object)p == null) // <-- wtf?
{
return false;
}
this code check if the cast went fine if not p should be null for the reason above
Note that this is the VS 2005 documentation. I guess the folks who write the documentation also had the same question and couldn't come up with a good answer; the example was changed for VS 2008. Here is the current version:
public bool Equals(TwoDPoint p)
{
// If parameter is null, return false.
if (Object.ReferenceEquals(p, null))
{
return false;
}
// Optimization for a common success case.
if (Object.ReferenceEquals(this, p))
{
return true;
}
// If run-time types are not exactly the same, return false.
if (this.GetType() != p.GetType())
return false;
// Return true if the fields match.
// Note that the base class is not invoked because it is
// System.Object, which defines Equals as reference equality.
return (X == p.X) && (Y == p.Y);
}

Is this the best approach using generics to check for nulls?

public static T IsNull<T>(object value, T defaultValue)
{
return ((Object.Equals(value,null)) | (Object.Equals(value,DBNull.Value)) ?
defaultValue : (T)value);
}
public static T IsNull<T>(object value) where T :new()
{
T defaultvalue = new T();
return IsNull(value, defaultvalue);
}
Have tested, and can use against data objects, classes and variables.
Just want to know if there is better way to go about this.
It looks like you're trying to duplicate the null coalesce operator:
var foo = myPossiblyNullValue ?? defaultValue;
First off, the method name is wrong. You imply that the result of the function is a boolean that is true exactly if the given value is null. In fact, that’s not the case. GetValueOrDefault might be a better name.
Secondly, you’re merely replicating the behaviour of the null coalesce operator, as mentioned by others.
Thirdly, your conditional is odd:
Object.Equals(value,null)) | (Object.Equals(value,DBNull.Value)
Why Object.Equals instead of ==? Better yet, use Object.ReferenceEquals since that makes it clear that you’re interested in reference equality. Also, you’re using the bitwise-or operator (|) which is semantically wrong in this context, although it happens to yield the right value. You want the boolean-or operator ||. (Also, inconsistency: why do you sometimes write object and other times Object?)
Finally, using type object instead of a generic type isn’t necessarily a good solution. It would be better to create overloads for generic reference and value types: this avoids boxing in the value types. It also means that you don’t have to specify the type explicitly in your second overload since it can be deduced from the method argument.
public static bool IsNull<T>(object value)
{
return object == default(T);
}
[Edited]
The following (non-generic) should work.
public static bool IsNull(object value)
{
return value == null;
}
Any value type will get boxed (i.e. non-null). Ref types will just be passed by pointer.

Categories

Resources