2014-10-01 2 views
0

У меня есть базовый класс «Entity» со следующим способом (я не реализующего IEquatable, это была огромная головная боль, так что я угробил этот подход)Как я могу получить класс, который принимает общий тип, для вызова метода из экземпляра этого типа?

virtual public bool Equals(Entity entity) 
    { 
     throw new Exception("The base Entity.Equals method should never be called"); 
    } 

У меня есть несколько классов, которые расширяют Entity. Каждый из них реализует метод Equals, что-то вроде этого.

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; 
    } 

Я действительно хочу иметь вход типа TestPlan вместо Object. (По крайней мере, я думаю, что делаю, я не хочу терять сильную типизацию).

Я понимаю, что этот метод не «переопределяет» базовый класс, потому что я сделал его виртуальным публичным, а не public override.

У меня есть метод, который принимает обобщенный тип, который будет вызывать .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; 
    } 

Проблема заключается в том, что exitingEntity.Equals() вызывает .equals базового класса.

Как я могу получить класс, который принимает общий тип, для вызова метода из экземпляра этого типа?

ответ

3

Просто переопределить базу Equals(object other) метод. Это достаточно просто.

Вы можете даже сделать его обязательным, объявляя это в Entity классе:

public override abstract bool Equals(object other); 
public override abstract int GetHashCode(); 

Теперь в классах, то Equals методы будут выглядеть следующим образом:

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)); 
} 

Теперь если вы хотят реализовать IEquatable<T> это будет действительно простой:

public bool Equals(TestPlan obj) 
{ 
    return Equals((object)obj); 
} 

Вы также можете сделать это наоборот:

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 
} 

О, и вы должны реализовать GetHashCode тоже для того, чтобы избежать неприятных сюрпризов:

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; 
} 

Это действительно важно. Кто-то из вашей команды может однажды использовать ваш объект в качестве ключа в словаре, например. Если вы правильно реализуете функции GetHashCode с самого начала, вы избежите таких ловушек в вашем будущем коде. Это небольшая цена, которую нужно заплатить сегодня за то, чтобы избежать больших WTF в будущем.

Здесь вы идете, это все, что вам действительно нужно.

+0

Что произойдет, если кто-то перейдет не по типу? Не будет var other = obj, поскольку TestPlan выдает исключение? Я не реализую IEquatable, мне еще нужно реализовать GetHashCode()?Каким будет преимущество реализации IEquatable, если вы сделаете это только с помощью одного метода? Этот код имеет единственную цель, чтобы проверить, совпадают ли записи базы данных при репликации. Таким образом, это не так, как мы ожидаем, что люди будут проходить объекты и сравнивать их все время. – Miebster

+1

@ Miebster Я расширю свой ответ. Но на данный момент 'obj как TestPlan' вернет' null', если 'obj' не является' TestPlan'. –

+0

@Miebster Вы не хотите переопределять Equals, а не GetHashCode. Некоторые из классов .Net (например, Dictionary) делают некоторые предположения с этими 2, которые вы действительно не хотите сломать. –

0

Чтобы переопределить функцию, аргументы должны быть одного и того же времени. Таким образом, ваш TestPlan.Equals должен быть похож на:

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; 
} 
Смежные вопросы