Reputation: 10728
I'm trying to implement operator==
in one of my classes. According to the book Microsoft Visual C# Step by Step I should write it like so:
using System;
using System.Diagnostics;
namespace EqualTest2
{
public class EqualTestClass
{
public double _x1;
public EqualTestClass(double x1)
{
_x1 = x1;
}
public override bool Equals(object other)
{
if (other is EqualTestClass)
{
return (Math.Abs(_x1 - ((EqualTestClass)other)._x1) < 1e-6);
}
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static bool operator ==(EqualTestClass lhs, EqualTestClass rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(EqualTestClass lhs, EqualTestClass rhs)
{
return !lhs.Equals(rhs);
}
}
class Program
{
static void Main(string[] args)
{
EqualTestClass test1 = new EqualTestClass(1.0);
EqualTestClass test2 = new EqualTestClass(1.0);
EqualTestClass test3 = new EqualTestClass(2.0);
EqualTestClass test4 = null;
Debug.WriteLine("1: {0}", test1 == test2);
Debug.WriteLine("2: {0}", test1 == test3);
Debug.WriteLine("3: {0}", test1 == test4);
Debug.WriteLine("4: {0}", test4 == test1);
}
}
}
This program throws NullReferenceException
on the fourth debug line because lhs
is null on the line lhs.Equals(rhs)
. I can't put if (lhs != null)
in operator==
because that causes infinite recursion (as the book warns). So in order to avoid an exception when comparing a null instance of my class, I changed the implementation to this:
public static bool operator ==(EqualTestClass lhs, EqualTestClass rhs)
{
try
{
return lhs.Equals(rhs);
}
catch (NullReferenceException)
{
return false;
}
}
public static bool operator !=(EqualTestClass lhs, EqualTestClass rhs)
{
try
{
return !lhs.Equals(rhs);
}
catch (NullReferenceException)
{
return false;
}
}
(I'm new to C# coming from an Objective C background where [lhs method:argument]
happily returns nil if lhs
is nil so an exception like this would never happen.)
Is this exception-based implementation idiomatically correct C#?
Upvotes: 2
Views: 494
Reputation: 2233
I would avoid using a try-catch block for your case. You need only change your operators to this:
public static bool operator ==(EqualTestClass lhs, EqualTestClass rhs)
{
return object.Equals(lhs, rhs);
}
public static bool operator !=(EqualTestClass lhs, EqualTestClass rhs)
{
return !object.Equals(lhs, rhs);
}
This will do the null-checking for you while still calling your overridden Equals()
method. According to the source code for System.Object.Equals()
:
public static bool Equals(Object objA, Object objB)
{
if (objA==objB) {
return true;
}
if (objA==null || objB==null) {
return false;
}
return objA.Equals(objB);
}
Looks like that takes care of your issue.
Upvotes: 4
Reputation: 1086
Simply do a null test first
if(lhs == null || rhs == null){
And handle that the way you want. (return false, or maybe true if both null)
.equals() requires an object and will throw NullPointer if you try to call it on a null object. But == works fine.
Upvotes: -1
Reputation: 2470
Consider using ReferenceEquals(lhs, null) to check the reference for null for each of your args before checking for equality
Upvotes: 4
Reputation: 63732
You need to compare the arguments by reference:
if (!ReferenceEquals(lhs, null)) ...
Upvotes: 1