简体   繁体   中英

Contains Returning False If Exist in List

I'm running into a problem where the contains method is return false even though it exist in the list. Can someone tell me what's wrong with this?

Program.CS

points.Add(new Point(-4, -7));
points.Add(new Point(0, 0));
points.Add(new Point(1, 2));
points.Add(new Point(-4, 5));
points.Insert(2, new Point(3, 1));
points.Add(new Point(7, -2));
points[0] = new Point(2, 1);
points.RemoveAt(2);

bool returnPoint = false;

returnPoint = points.Contains(new Point(1, 2));

PointList.CS

public bool Contains(Point item)
{
   return _Points.Contains(item);
}

Point.CS

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

public Point(int x, int y)
{
    X = x;
    Y = y;
}

Since Point is a class, it is a reference type. By default, reference types check for referential equality. If you want to get the behavior you're expecting, you should override the Equals and GetHashCode methods in Point , and it probably wouldn't hurt to implement IEquatable<Point> while you're at it, along with the == and != operators.

An example implementation would look like this:

public class Point : IEquatable<Point>
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

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

        return X == other.X && Y == other.Y;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        if (obj.GetType() != this.GetType())
            return false;

        return Equals((Point)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (X * 397) ^ Y;
        }
    }

    public static bool operator ==(Point left, Point right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Point left, Point right)
    {
        return !Equals(left, right);
    }
}

If that seems like a lot, well, it is. Unfortunately, implementing equality tends to require a good amount of boiler plate in C#. If we get Record types in C# 8 some of the pain may be alleviated, but until then this is the typical approach.

Contains in ArrayList uses implementation of Equals() on the objects. Currently you are checking if object references are equal.

Point point = new Point(5, 2);
Point refPoint = point; // refer to same object
points.Add(point);

bool returnPoint = false;

returnPoint = points.Contains(refPoint); // return true

Need to override Equals() and GetHashcode in your class for reference types:

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

 if(otherPoint != null) 
    return (X.Equals(otherPoint.X) && (Y.Equals(otherPoint.Y)));

   return false;
}

Point is a reference type, so you're unintentionally comparing references, not properties.

You can compare properties by using LINQ's Any() and passing a lambda expression that performs the comparison you wish.

//using System.Linq;
returnPoint = points.Any( p => p.X == 1 && p.Y == 2 );

you need valueObject for best practice solution and For comparison only x and y may not. you should think of functional processes as DDD design look here

 public abstract class ValueObject
    {
        protected static bool EqualOperator(ValueObject left, ValueObject right)
        {
            if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
            {
                return false;
            }
            return ReferenceEquals(left, null) || left.Equals(right);
        }

        protected static bool NotEqualOperator(ValueObject left, ValueObject right)
        {
            return !(EqualOperator(left, right));
        }
        protected abstract IEnumerable<object> GetAtomicValues();

        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() != GetType())
            {
                return false;
            }
            var other = (ValueObject)obj;
            var thisValues = GetAtomicValues().GetEnumerator();
            var otherValues = other.GetAtomicValues().GetEnumerator();
            while (thisValues.MoveNext() && otherValues.MoveNext())
            {
                if (ReferenceEquals(thisValues.Current, null) ^ ReferenceEquals(otherValues.Current, null))
                {
                    return false;
                }
                if (thisValues.Current != null && !thisValues.Current.Equals(otherValues.Current))
                {
                    return false;
                }
            }
            return !thisValues.MoveNext() && !otherValues.MoveNext();
        }

        public override int GetHashCode()
        {
            return GetAtomicValues()
               .Select(x => x != null ? x.GetHashCode() : 0)
               .Aggregate((x, y) => x ^ y);
        }
    }

your PointList.cs

    public class PointList
{
    public string Bla { get; set; }

    public List<Point> Points { get; protected set; } = new List<Point>();

    public void AddPoint(int x, int y)
    {
        AddPoint(new Point(x, y));
    }
    public void AddPoint(Point p)
    {
        if (!Points.Any(x => x.Equals(p)))
            Points.Add(p);
    }
    public void RemovePoint(int x, int y)
    {
        RemovePoint(new Point(x, y));
    }
    public void RemovePoint(Point point)
    {
        Points.Remove(point);
    }
    public Point GetPoint(int x, int y)
    {
        return GetPoint(new Point(x, y));
    }
    public Point GetPoint(Point point)
    {
        return Points.FirstOrDefault(x => x.Equals(point));
    }
}

your Point.cs

public class Point : ValueObject
    {
        public int X { get; set; }
        public int Y { get; set; }
        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
        protected override IEnumerable<object> GetAtomicValues()
        {
            yield return X;
            yield return Y;
        }
    }

Examples

 class Program
    {
        static void Main(string[] args)
        {
            var list = new PointList();
            list.AddPoint(1, 1);
            list.AddPoint(1, 2);
            list.AddPoint(14, 53);


            list.RemovePoint(1, 1);
            list.RemovePoint(new Point(1, 2));


            var p2 = list.GetPoint(14, 53);
            var p1 = list.GetPoint(new Point(14, 53));


        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM