使用 LINQ GroupBy 按引用对象而不是值对象分组
Using LINQ GroupBy to group by reference objects instead of value objects
我想对记录列表中的多个对象进行分组,而不仅仅是多个值。
我在使用引用类型对象进行分组时遇到问题。我有一个包含 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});
为了使此代码正常工作,我必须调用我们对这些对象的特定 属性 进行分组。问题是我需要存储在分组 "Key" 中的复杂对象,以便我可以访问该组的特定信息
var groups = collection
.Where(g => g.Stage == InventoryStage.StageA)
.GroupBy(g => new {
Birthday = g.BirthDate,
RoomName = g.Room.Name,
TypeName = g.Type.Name
});
我最终不得不做 ^ 来使分组工作,但是这些组丢失了我想要的复杂对象。
要完成此任务,您可以覆盖 类:
的 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();
}
}
查看 以获得更复杂的示例
- 您可以覆盖包含这些属性的主要 class 中的
Equals
+ GetHashCode
,而不是使用 GroupBy
中的匿名类型。
- 另一种方法是实施自定义
IEqualityComparer<YourMainType>
。您可以使用它的一个实例来重载 GroupBy
.
- 您的
Room
和 Type
可以覆盖 Equals
+ GetHashCode
or/and 实现 IEquatable<T>
。实现 IEquatable
/IEquatable<>
是不够的,因为 GroupBy
在开始与 Equals
比较对象之前首先使用 GetHashCode
来确定哈希码,所以这是初始的过滤器。
这里是 class 房间的示例:
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;
}
}
现在您甚至可以将复杂类型用作匿名类型的 属性。
我想对记录列表中的多个对象进行分组,而不仅仅是多个值。
我在使用引用类型对象进行分组时遇到问题。我有一个包含 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});
为了使此代码正常工作,我必须调用我们对这些对象的特定 属性 进行分组。问题是我需要存储在分组 "Key" 中的复杂对象,以便我可以访问该组的特定信息
var groups = collection
.Where(g => g.Stage == InventoryStage.StageA)
.GroupBy(g => new {
Birthday = g.BirthDate,
RoomName = g.Room.Name,
TypeName = g.Type.Name
});
我最终不得不做 ^ 来使分组工作,但是这些组丢失了我想要的复杂对象。
要完成此任务,您可以覆盖 类:
的 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();
}
}
查看
- 您可以覆盖包含这些属性的主要 class 中的
Equals
+GetHashCode
,而不是使用GroupBy
中的匿名类型。 - 另一种方法是实施自定义
IEqualityComparer<YourMainType>
。您可以使用它的一个实例来重载GroupBy
. - 您的
Room
和Type
可以覆盖Equals
+GetHashCode
or/and 实现IEquatable<T>
。实现IEquatable
/IEquatable<>
是不够的,因为GroupBy
在开始与Equals
比较对象之前首先使用GetHashCode
来确定哈希码,所以这是初始的过滤器。
这里是 class 房间的示例:
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;
}
}
现在您甚至可以将复杂类型用作匿名类型的 属性。