集合元素比较

如果有个类对象的集合,要判断一个对象是不是存在这个集合中,可以用Contains方法判断。但我们都知道这判断是引用。假设这个集合里面存在和这个对象所有的值成员的值都相等的元素,我们就认为这个对象存在于这个集合中,那么我们该如果做? 我能想到就是重写Object基类中的Equals方法,然后为这个集合添加一个扩展方法。如下:

public class Racer 
 {
        public Racer(string firstName, string lastName, string country = "", int wins = 0)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Country = country;
            this.Wins = wins;   
        }

        public string FirstName { get; private set; }

        public string LastName { get; private set; }

        public string Country { get; private set; }

        public int Wins { get; private set; }

        public override bool Equals(object obj)
        {
            Racer other = obj as Racer;
            if (other == null)
                return false;

            return FirstName == other.FirstName
                && LastName == other.LastName
                && Country == other.Country
                && Wins == other.Wins;
        }

  }

List<Racer>的扩展方式:

public static bool HasItem(this List<Racer> listR, Racer racer)
        {
            return listR.Any(x => x.Equals(racer));
        }

然后我们就可以调用HasItem判断,测试一下:

List<Racer> listRacer = new List<Racer>();
            listRacer.Add(new Racer("xixiao", "meng","china"));
            listRacer.Add(new Racer("zhstar", "zhou","china"));
            
            Racer racer = new Racer("zhstar", "zhou","china");

            Console.WriteLine("listRacer HasItem racer:{0}", listRacer.HasItem(racer));
            Console.WriteLine("listRacer Contains racer:{0}", listRacer.Contains(racer));

运行代码代码我们发现HasItem方法和Contains方法都返回了True。这是为什么呢?跟踪调试发现,原来Contains方法也是通过我们重写的Equals方法来判断的。原来如此,于是我们可以删掉扩展方法直接使用系统的Contains方法了。那是不是Contains的判断一定就是调用基类中Equals方法呢?

我们修改一下Racer类,让它集成IEquatable接口,实现Equals方法,让它返回引用比较的结果:

View Code
public class Racer :IEquatable<Racer>
    {
        public Racer(string firstName, string lastName, string country = "", int wins = 0)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Country = country;
            this.Wins = wins;   
        }

        public string FirstName { get; private set; }

        public string LastName { get; private set; }

        public string Country { get; private set; }

        public int Wins { get; private set; }

        public override bool Equals(object obj)
        {
            Racer other = obj as Racer;
            if (other == null)
                return false;

            return FirstName == other.FirstName
                && LastName == other.LastName
                && Country == other.Country
                && Wins == other.Wins;
        }

        public bool Equals(Racer other)
        {
            return object.ReferenceEquals(this, other);
        }
    }

在按照前面那样测试一下Contains和HasItem方法,我们会发现返回的结果都是false。这是不是说明了对于Equals方法,如果实现了IEquatable接口,那么会首先使用这个接口的Equals方法,如果没有实现这个接口就会使用基类的或者重写基类的Equals方法呢?

我们再修改一下Racer类,把IEquatable接口去掉,但保留Equals方法:

View Code
public class Racer
    {
        public Racer(string firstName, string lastName, string country = "", int wins = 0)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Country = country;
            this.Wins = wins;   
        }

        public string FirstName { get; private set; }

        public string LastName { get; private set; }

        public string Country { get; private set; }

        public int Wins { get; private set; }

        public override bool Equals(object obj)
        {
            Racer other = obj as Racer;
            if (other == null)
                return false;

            return FirstName == other.FirstName
                && LastName == other.LastName
                && Country == other.Country
                && Wins == other.Wins;
        }

        public bool Equals(Racer other)
        {
            return object.ReferenceEquals(this, other);
        }
    }

再运行一下,会发现HasItem方法返回了false,但Contains方法却返回True。

到这里,其实就很明白,对集合来说,它是一个泛型的类,无法知道每个类型具体的成员,在判断一个元素或者查找一个元素的时候,首先依赖的是IEquatable接口的Equals方法,如果没有继承这个接口那么就使用基类中的Equals方法。但我们在调用对象实例里面的方法,它就会找到那个最适合被调用的方法。比如上面的例子中如果我们把扩展方法的第二个参数该成object类型,就会调用我们重写的基类的Equals方法。

原文地址:https://www.cnblogs.com/zhstar/p/2659222.html