【问题标题】:Using LINQ GroupBy to group by reference objects instead of value objects使用 LINQ GroupBy 按引用对象而不是值对象进行分组
【发布时间】:2016-08-04 08:01:11
【问题描述】:

我想对记录列表中的多个对象进行分组,而不仅仅是多个值。

我无法将分组用于引用类型对象。我有一组包含 Room、Type 和 DateTime 的对象。 Room、Type 和 DateTime 都有与之关联的属性。我已经在房间中添加了 IEquateable 接口,并且类型思维足以与 group by 一起使用。

var groups = collection
  .Where(g => g.Stage == InventoryStage.StageA)
  .GroupBy(g => new {g.BirthDate, g.Room, g.Type});

为了让这段代码正常工作,我必须调用这些对象上的特定属性以进行分组。问题是我需要存储在分组“键”中的复杂对象,以便我可以访问该组的特定信息

var groups = collection
  .Where(g => g.Stage == InventoryStage.StageA)
  .GroupBy(g => new {
     Birthday = g.BirthDate, 
     RoomName = g.Room.Name, 
     TypeName = g.Type.Name
   });

我最终不得不做 ^ 来让分组工作,但是这些组失去了我想要的复杂对象。

【问题讨论】:

  • 您的RoomType 应该覆盖Equals+GetHashCode 或/并实现IEquatable<T>

标签: c# linq grouping ienumerable iequatable


【解决方案1】:

要完成此任务,您可以为您的类重写 Equals() 和 GetHashCode() 方法:

public class Room {
     public string Name;
     public string Foo;

     public override bool Equals(object obj)
     {
         Room other = obj as Room;
         if (other == null) return false;
         return this.Name == other.Name && this.Foo == other.Foo;
     }

     public override int GetHashCode()
     {
         return (Name.GetHashCode() ^ Foo.GetHashCode()).GetHashCode();
     }
}

查看here 了解更复杂的示例

【讨论】:

    【解决方案2】:
    1. 您可以在包含这些属性的主类中覆盖Equals + GetHashCode,而不是在GroupBy 中使用匿名类型。
    2. 另一种方法是实现自定义IEqualityComparer<YourMainType>。你可以使用它的一个实例来重载GroupBy
    3. 您的RoomType 可以覆盖Equals + GetHashCode 或/并实现IEquatable<T>。实现IEquatable/IEquatable<> 是不够的,因为GroupBy 在开始将对象与Equals 进行比较之前首先使用GetHashCode 确定哈希码,所以这是初始过滤器。

    这是 Room 类的示例:

    public class Room:IEquatable<Room>
    {
        public Room(string name)
        {
            Name = name;
        }
    
        public string Name { get; }
    
        /// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
        /// <returns>true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.</returns>
        /// <param name="other">An object to compare with this object.</param>
        public bool Equals(Room other)
        {
            return String.Equals(this.Name, other?.Name);
        }
    
        /// <summary>Determines whether the specified object is equal to the current object.</summary>
        /// <returns>true if the specified object  is equal to the current object; otherwise, false.</returns>
        /// <param name="obj">The object to compare with the current object. </param>
        public override bool Equals(object obj)
        {
            if(ReferenceEquals(this, obj))
                return true;
            Room other = obj as Room;
            return this.Equals(other);
        }
    
        /// <summary>Serves as the default hash function. </summary>
        /// <returns>A hash code for the current object.</returns>
        public override int GetHashCode()
        {
            return Name?.GetHashCode() ?? Int32.MinValue;
        }
    }
    

    现在您甚至可以将复杂类型用作匿名类型的属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 2013-09-05
      • 2011-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多