Как я могу переопределить оператор == базового класса, чтобы вызвать переопределение - PullRequest
6 голосов
/ 26 июня 2010

С кодом, подобным следующему

public class Task
{
  string Name;
  public static bool operator ==(Task t1, Task t2)
  { return t1.Name = t2.Name && t1.GetType() == t2.GetType(); }
}
public class TaskA : Task
{
   int aThing;
   public static bool operator ==(TaskA t1, TaskA t2)
   { 
      return (Task)t1 == (Task)t2 && t1.GetType() == t2.GetType()
          && t1.aThing == t2.aThing; }
}
public class TaskB : Task  //more of the same

class Stuffin
{
   List<Task> Tasks;

   void CheckIt()
   {
      bool theSame = Tasks[0] == Tasks[1];
   }

Я пытаюсь убедиться, что производный оператор (TaskA. ==) вызван.

Я получаю ошибку компиляции при попытке использовать технику здесь .

Я думаю, что смог бы заставить его работать правильно, если бы оператор не был статичным, потому что тогда я мог бы переопределить оператор базового класса. Это возможно?

Как только я получу это, как мне сравнить базовые свойства (я думаю, приведение к типу задачи [(Task) t1 == (Task) t2] не будет работать)?

Ответы [ 5 ]

10 голосов
/ 26 июня 2010

Вы не можете. Операторы не переопределены , они перегружены . Это означает, что используемая реализация полностью определяется во время компиляции.

Одна вещь, которую вы можете сделать, это переопределить Equals в Task и вызвать ее с ==, а затем переопределить снова в TaskA. Это также облегчает проверку "базовых свойств" - просто позвоните base.Equals из TaskA.Equals.

7 голосов
/ 26 июня 2010

То, что вы пытаетесь сделать, на самом деле довольно сложно в C #.В основном вам нужен оператор, чье поведение определяется во время выполнения на основе runtime типов обоих аргументов.Это сложно;Оператор == отправляется на основе типов времени компиляции обоих операндов, а метод .Equals отправляется на основе времени выполнения типа получателя тип времени компиляции аргумента .

Стандартным способом реализации двойной диспетчеризации в языке, который поддерживает только одну виртуальную диспетчеризацию, является шаблон посетителя.Вы могли бы изучить это.

Для дальнейшего чтения по этой теме вы можете проверить мою статью здесь:

http://blogs.msdn.com/b/ericlippert/archive/2009/04/09/double-your-dispatch-double-your-fun.aspx

2 голосов
/ 26 июня 2010

Этот пост был о C ++.Рассматривайте оператор как статическую функцию.Вы не можете перегрузить это.

Но вы можете объявить экземпляр виртуального метода и вызвать его внутри своего оператора.Но оператор note принимает два аргумента, и они могут иметь разный фактический тип, поэтому вам нужно решить, как выбрать один аргумент из этих двух.

public class Task
{
     public virtual bool MyMethod(Task anotherTask) { return true; }

     public static bool operator==(Task t1, Task t2) 
     {
          return t1 == null ? false : t1.MyMethod(t2);
     } 
}

public class TaskA
{
      public override bool MyMethod(Task anotherTask) { return false; }
}
1 голос
/ 26 июня 2010

Если вы можете сделать Task абстрактным классом, шаблон шаблонного метода мог бы подойти.

public abstract class Task
{
    string Name;
    protected abstract bool DoEquals( Task rhs );

    public static bool operator ==(Task t1, Task t2)
    {
        return t1.DoEquals( t2 );
    }
}

public class TaskA : Task
{
    protected bool DoEquals( Task rhs )
    {
        return /* custom compare */
    }
}

public class TaskB : Task
{
    protected bool DoEquals( Task rhs )
    {
        return /* custom compare */
    }
}
0 голосов
/ 29 июня 2010

Мое гибридное решение, которое, кажется, работает.

public class Task
{
  string Name;
  public static bool operator ==(Task t1, Task t2)
  { 
    if ((object)t1 == null || (object)t2 == null)
    {
      return (object)t1 == null && (object)t2 == null;
    }

    return t1.Name == t2.Name && t1.GetType() == t2.GetType(); }
  public virtual bool Equals(Task t2)
  {
     return this == t2;
  }
}

public class TaskA : Task
{
  int aThing;
  public static bool operator ==(TaskA t1, TaskA t2)
  { 
    if ((object)t1 == null || (object)t2 == null)
    {
      return (object)t1 == null && (object)t2 == null;
    }

    return (Task)t1 == (Task)t2 && t1.aThing == t2.aThing;
  }
  public override bool Equals(Task t2)
  {
    return this == t2 as TaskA;
  }
}
...