Miebster
Miebster

Reputation: 2404

How can I get a class that takes generic type, to call a method from an instance of that type?

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

Answers (2)

Lucas Trzesniewski
Lucas Trzesniewski

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

Dave Mackersie
Dave Mackersie

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

Related Questions