Reputation: 2404
I have a base class "Entity" with the following method (I'm not implementing IEquatable, that was a huge headache so I ditched that approach)
virtual public bool Equals(Entity entity)
{
throw new Exception("The base Entity.Equals method should never be called");
}
I have several classes that extend Entity. Each one will implement an Equals method, something like this.
virtual public bool Equals(TestPlan other)
{
if (this.TestPlanType.Equals(other.TestPlanType) &&
this.Name.Equals(other.Name) &&
this.Description.Equals(other.Description) &&
this.DatetimeCreated.Equals(other.DatetimeCreated) &&
this.UserNameCreated.Equals(other.UserNameCreated) &&
this.Duration.Equals(other.Duration) &&
this.Scenarios.SequenceEqual(other.Scenarios)) return true;
return false;
}
I really want to have the input be of type TestPlan instead of Object. (At least I think I do, I don't want to lose strong typing).
I realize this method doesn't "override" the base class because I made it virtual public instead of public override.
I have a method that takes a generic type that will call .Equals()
public int GetIdenticalEntityId<T>(T entity) where T : Entity
{
List<T> exitingEntities = LoadEntities<T>();
foreach (T existingEntity in exitingEntities)
{
if (existingEntity.Equals(entity))
{
return existingEntity.Id;
}
}
return -1;
}
The problem is that the exitingEntity.Equals() calls the base class .Equals.
How can I get a class that takes generic type, to call a method from an instance of that type?
Upvotes: 0
Views: 131
Reputation: 51430
Just override the base Equals(object other)
method. It's simple enough.
You could even make it mandatory, by declaring this in your Entity
class:
public override abstract bool Equals(object other);
public override abstract int GetHashCode();
Now, in your classes, the Equals
methods would look like this:
public override bool Equals(object obj)
{
var other = obj as TestPlan;
if (other == null)
return false;
if (ReferenceEquals(other, this))
return true;
return this.TestPlanType.Equals(other.TestPlanType) &&
this.Name.Equals(other.Name) &&
this.Description.Equals(other.Description) &&
this.DatetimeCreated.Equals(other.DatetimeCreated) &&
this.UserNameCreated.Equals(other.UserNameCreated) &&
this.Duration.Equals(other.Duration) &&
this.Scenarios.SequenceEqual(other.Scenarios));
}
Now if you want to implement IEquatable<T>
it will be really easy:
public bool Equals(TestPlan obj)
{
return Equals((object)obj);
}
You can also do this the other way around:
public override bool Equals(object obj)
{
return Equals(obj as TestPlan);
}
public bool Equals(TestPlan obj)
{
if (obj == null)
return false;
// Same code as before
}
Oh, and you should implement GetHashCode
too in order to avoid nasty surprises:
public override int GetHashCode()
{
var hash = TestPlanType.GetHashCode();
hash = (hash * 397) ^ Name.GetHashCode();
hash = (hash * 397) ^ Description.GetHashCode();
hash = (hash * 397) ^ DatetimeCreated.GetHashCode();
hash = (hash * 397) ^ UserNameCreated.GetHashCode();
hash = (hash * 397) ^ Duration.GetHashCode();
hash = (hash * 397) ^ Scenarios.GetHashCode();
return hash;
}
This is really important. Someone in your team may one day want to use your object as a key in a dictionary for instance. If you properly implement the GetHashCode
functions from the start you will avoid such traps in your future code. This is a small price to pay today for avoiding big WTFs in the future.
Here you go, it's all you really need.
Upvotes: 3
Reputation: 1061
In order to override a function, the arguments must be of the same time. So your TestPlan.Equals should be similar to:
override public bool Equals(Entity entity)
{
TestPlan other = entity as TestPlan;
if (other == null)
return false;
if (this.TestPlanType.Equals(other.TestPlanType) &&
this.Name.Equals(other.Name) &&
this.Description.Equals(other.Description) &&
this.DatetimeCreated.Equals(other.DatetimeCreated) &&
this.UserNameCreated.Equals(other.UserNameCreated) &&
this.Duration.Equals(other.Duration) &&
this.Scenarios.SequenceEqual(other.Scenarios)) return true;
return false;
}
Upvotes: 0