运算符重载给出错误

时间:2014-11-06 08:57:43

标签: c# .net

我有一个名为Point的类,它正在重载" =="和"!="运算符比较两个Point对象。如何将我的Point对象与" null"进行比较,这是一个问题,因为当我调用==或!=运算符时,null为Equals方法中的问题。请打开一个控制台应用程序,看看我想说什么。如何解决它。

public class Point
    {
        public int X { get; set; }
        public int Y { get; set; }


        public static bool operator == (Point p1,Point p2)
        {
            return p1.Equals(p2);
        }

        public static bool operator != (Point p1, Point p2)
        {
            return !p1.Equals(p2);
        }


        public override bool Equals(object obj)
        {
            Point other = obj as Point;

            //problem is here calling != operator and this operator calling  this method again
            if (other != null)
            {
                if (this.X == other.X && this.Y == other.Y)
                {
                    return true;
                }
                return false;
            }

            else
            {
                throw new Exception("Parameter is not a point");
            }
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            Point p1 = new Point { X = 9, Y = 7 };
            Point p2 = new Point { X = 5, Y = 1 };

            p1.X = p2.X;
            p1.Y = p2.Y;

            bool b1=p1==p2;

            Console.ReadKey();
        }
    }

4 个答案:

答案 0 :(得分:4)

使用ReferenceEquals检查null

if (ReferenceEquals(other, null))

话虽如此,Equals如果遇到未知对象类型通常不会抛出异常,它应该只返回false,因此这是我要编写的方法:

public override bool Equals(object obj)
{
    Point other = obj as Point;

    if (ReferenceEquals(other, null))
        return false;

    return (this.X == other.X && this.Y == other.Y);
}

另一个问题是,如果您将null与某些内容进行比较,您的运算符将抛出异常,因为您无法在null引用上调用实例方法。

因此,这是我写的完整课程:

public class Point
{
    public int X { get; set; }
    public int Y { get; set; }


    public static bool operator == (Point p1,Point p2)
    {
        if (ReferenceEquals(p1, p2)) return true;
        if (ReferenceEquals(p1, null)) return false;
        return p1.Equals(p2);
    }

    public static bool operator != (Point p1, Point p2)
    {
        return !(p1 == p2);
    }

    public bool Equals(Point other)
    {
        if (ReferenceEquals(other, null))
            return false;

        return (this.X == other.X && this.Y == other.Y);
    }

    public override bool Equals(object obj)
    {
        Point other = obj as Point;
        if (ReferenceEquals(other, null))
            return false;
        return Equals(other);
    }
}

答案 1 :(得分:1)

您不应该在以下位置抛出异常:

        if (other != null)
        {
            ...
        }
        else
        {
            throw new Exception("Parameter is not a point");
        }

您可以阅读http://msdn.microsoft.com/en-US/library/336aedhh%28v=vs.85%29.aspx,了解Equals()如何正确实施。

答案 2 :(得分:1)

在C#中处理相等性可能很棘手,并且很容易陷入像你在这里遇到过的陷阱。

在处理相等时,我总是遵循相同的模式,无论是在值类型中还是在引用类型中(显然除了null检查):实现一个静态的私有帮助器方法来处理所有可能性,并让所有等式检查都会调用此方法。

因此,在您的情况下,我会执行以下操作:

更新 :修正了一个拼写错误,equals应该是private,而不是public

 private static bool equals(Point p1, Point p2)
 {
     if (object.ReferenceEquals(p1, p2))
         return true;

     if (object.ReferenceEquals(p1, null) || object.ReferenceEquals(p2, null))
         return false;

     return p1.X == p2.X && p1.Y == p2.Y;
 }

好的,那我们在这做什么呢?

  1. 我们首先检查两个对象是否具有相同的引用。如果 就是这样,那么它们必须是平等的,因为它们是相同的 宾语。请注意,这会处理null == null案例。

  2. 然后我们检查两个参数中的任何一个是否等于null。 如果是,那么我们就知道p1p2不相等。

    要查看参数是否等于null,我们使用satic方法 bool object.ReferenceEquals(,)以避免您遇到的问题 这又是你的平等实施。

  3. 最后,我们现在知道我们有两个非空Point参数,所以我们去了 提前并实现两个Point对象的特定相等逻辑。

  4. 通过这种简单的方法,我们在课堂上处理了所有可能的等式检查。现在我们只需要从所有可能的相等方法和运算符中调用此方法:

    public static bool operator ==(Point p1, Point p2)
    {
        return Point.equals(p1, p2);
    }
    
    public static bool operator !=(Point p1, Point p2)
    {
        return !Point.equals(p1, p2);
    }
    
    public override bool Equals(object obj)
    {
        return Point.equals(this, obj as Point);
    }
    

    另外,您应该实现非常简单的IEquatable<Point>接口。这在处理值类型时特别相关,因为在执行相等性检查时避免装箱转换:

    public bool Equals(Point p)
    {
        return Point.equals(this, p);
    }
    

    最后但并非最不重要的是,您要覆盖Equals方法以及==!=运算符,因此您还应该以与您的平等一致的方式覆盖int GetHashCode()实施:如果p1 == p2,那么p1.GetHashCode() 必须等于p1.GetHashCode()(注意,这并不意味着如果p1 != p2p1.GetHashCode()必须不等于p2.GetHashCode()):

    public override int GetHashCode()
    {
        return this.X ^ this.Y;
    }
    

    希望这个小指南有所帮助。

答案 3 :(得分:0)

也许是这样的:

public override bool Equals(object obj)
{
    if (obj != null && obj is Point)
    {
       Point other = (Point)obj;
       if (this.X == other.X && this.Y == other.Y)
       {
           return true;
       }
       return false;
    }
    return false;
}