【问题标题】:How can i override a base class's == operator, so the override gets called如何覆盖基类的 == 运算符,以便调用覆盖
【发布时间】:2010-06-25 21:46:05
【问题描述】:

使用如下代码

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.==)。

我在尝试here 技术时遇到编译错误。

如果运算符不是静态的,我想我可以让它正常工作,因为我可以覆盖基类的运算符。这可能吗?

一旦我知道了,我将如何比较基本属性(我认为转换为任务类型 [(Task)t1 == (Task)t2] 不起作用)?

【问题讨论】:

    标签: c# operator-overloading equals-operator


    【解决方案1】:

    你不能。运算符没有被覆盖,它们被重载。这意味着要使用的实现完全在编译时决定。

    可以做的一件事是在Task 中覆盖Equals 并从== 中调用它,然后在TaskA再次覆盖它。这也使“基本属性”检查变得容易 - 只需从 TaskA.Equals 调用 base.Equals

    【讨论】:

      【解决方案2】:

      您尝试做的事情在 C# 中确实非常困难。基本上你想要的是一个操作符,它的行为是在运行时根据 both 参数的 runtime 类型确定的。这很难; == 操作符是根据两个操作数的compile time 类型分派的,.Equals 方法是根据receiverruntime 类型分派的em> 但编译时间类型的参数

      在只支持单虚拟分派的语言中实现双分派的标准方法是访问者模式。你可以调查一下。

      如需进一步阅读此主题,您可以在此处查看我的文章:

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

      【讨论】:

      • 考虑到两种类型相同的要求,我认为在这种情况下并不难——Task.Equals(TaskA)TaskA.Equals(Task)(就运行时类型而言)都应该返回 false通过GetType() 进行比较 - 所以类型不同的实现点并不重要。在更一般的情况下,这肯定更难。
      • 在这里使用dynamic 来获取基于运行时类型的行为不是很简单吗?
      【解决方案3】:

      那篇文章是关于 C++ 的。 将运算符视为静态函数。你不能超载它。

      但是,你可以声明实例虚方法,并在你的操作符中调用它。但是注意运算符接受两个参数,它们可能具有不同的实际类型,因此您需要决定如何从这两个参数中选择一个。

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

      【讨论】:

        【解决方案4】:

        如果您可以使 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 */
            }
        }
        

        【讨论】:

        • 任务已实例化,我使用的是 Fwx3.5,所以我想我需要做类似这样的事情或 Skeet 的事情。我只需要告诉客户调用该方法而不是调用 == 运算符,以避免任何混淆。
        【解决方案5】:

        我的混合解决方案似乎有效。

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

        【讨论】: