zoukankan      html  css  js  c++  java
  • 怎么使用LINQ方法来比较自定义类型对象

     LINQ提供了方便的语法和很多操作对象集合的有用的方法。但是,要让LINQ比较方法,如Distinct或Intersect能正确处理,类型必须要满足一些条件。让我们看看Distinct方法,它从集合中返回所有的不重复对象。

     

    List<int> numbers = new List<int> { 1, 1, 2, 3 };

    var distinctNumbers = numbers.Distinct();

    foreach (var number in distinctNumbers)

        Console.WriteLine(number);

     

    输出: 1 2 3

     

    但是如果你想在你自定义类型对象的集合使用Distinct方法呢?例如,像这样:

     

    class Number

    {

        public int Digital { get; set; }

        public String Textual { get; set; }

    }

     

    class Program

    {

        static void Main(string[] args)

        {

           List<Number> numbers = new List<Number> {

               new Number { Digital = 1, Textual = "one" },

               new Number { Digital = 1, Textual = "one" } ,

               new Number { Digital = 2, Textual = "two" } ,

               new Number { Digital = 3, Textual = "three" } ,

               };

     

           var distinctNumbers = numbers.Distinct();

     

           foreach (var number in distinctNumbers)

                       Console.WriteLine(number.Digital);

        }

    }

     

     

    代码可以通过编译,但输出却不一样:1 1 2 3

     

    为什么会这样?答案在LINQ的实现细节里。要让Distinct方法正确处理,类型必须重写object的Equals和GetHashCode方法便可,并必须实现IEquatable<T>

     

    那么,上个例子的Number类实际上需要看起来像这样:

     

     

    class Number: IEquatable<Number>

    {

        public int Digital { get; set; }

        public String Textual { get; set; }

     

        public bool Equals(Number other)

        {

     

            // 检查被比较的对象是否为null。

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

     

            // 检查是否引用的相同对象。

            if (Object.ReferenceEquals(this, other)) return true;

     

            // 检查对象的属性是否相等。

     

            return Digital.Equals(other.Digital) &&

     

                   Textual.Equals(other.Textual);

        }

     

        // 如果比较两个对象是相等的,

        // 那么这两个对象的GetHashCode方法必须返回一样的值。

     

        public override int GetHashCode()

        {

            // 如果Textual字段不为空,则获取它的哈希值。

            int hashTextual = Textual == null ? 0 : Textual.GetHashCode();

     

            // 获取Digital字段的哈希值

            int hashDigital = Digital.GetHashCode();

     

            // 计算对象的哈希值。

            return hashDigital ^ hashTextual;

        }

    }

     

    但假如你无法改变此类型呢?如果它在一个库里而你没有办法让此类型实现IEquatable<T>接口呢?答案是创建一个你自己的比较器然后将其通过参数传递给Distinct方法。

     

    相等比较器必须实现IEqualityComparer<T>接口,且同样提供GetHashCode和Equals方法。

     

    这里是怎么为原Number类实现相等比较器,大概像这样:

     

    class NumberComparer : IEqualityComparer<Number>

    {

        public bool Equals(Number x, Number y)

        {

            if (Object.ReferenceEquals(x, y)) return true;

     

            if (Object.ReferenceEquals(x, null) ||

                Object.ReferenceEquals(y, null))

                    return false;

     

                return x.Digital == y.Digital && x.Textual == y.Textual;

        }

     

        public int GetHashCode(Number number)

        {

            if (Object.ReferenceEquals(number, null)) return 0;

     

            int hashTextual = number.Textual == null

                ? 0 : number.Textual.GetHashCode();

     

            int hashDigital = number.Digital.GetHashCode();

     

            return hashTextual ^ hashDigital;

        }

    }

     

    不要忘记将比较器传递给Distinct方法:

     

    var distinctNumbers = numbers.Distinct(new NumberComparer());

     

    当然,这个规则不仅仅适用于Distinct方法。例如,同样可以用于Contains,Except,Intersect,和Union方法。通常,如果你看到此LINQ方法有个接受IEqualityComparer<T>参数的重载,这可能表示对你自己的类型使用此方法时,你需要在你的类中实现IEquatable<T>接口或创建你自己的相等比较器

     

  • 相关阅读:
    while语句的使用
    Sql Server2008忘记sa登陆密码
    C# 读取Excel到DataTable两种方式对比
    读《太阳照常升起》-海明威
    年终总结-2019 混沌收获
    如何在调试状态下部署局域网网站
    HTML-文本标签
    HTML-表单
    HTML-入门
    正则表达式大全
  • 原文地址:https://www.cnblogs.com/supperwu/p/LINQ.html
Copyright © 2011-2022 走看看