以下是示例:
class A
{
public long ParentId;
public string ParentName;
public string Name;
}
// list is IEnumerable<A>
var selected = list
.Select(x => new {
parent = new {
id = x.ParentId,
name = x.ParentName
}
name = x.Name
});
var grouped = selected.GroupBy(x => x.parent);
因此,在分组成功完成后,我得出结论,如果两个实体都具有相同的parent
和ParentId
,则不会为两个不同的实体创建ParentName
。换句话说,如果list[i].ParentId == list[j].ParentId
和list[i].ParentName == list[j].ParentName
,则选择selected[i].parent == selected[j].parent
后
我对吗?我想,new
通过源集合在每次迭代中创建新对象。 .NET如何做到这一点?
答案 0 :(得分:4)
这是Equals如何受到重视的问题。对于匿名类,当且仅当属性匹配时才返回true,并且对于每个属性都是相等的。
比较这两个:
Console.WriteLine(new { A = 1, B = "a" } == new { A = 1, B = "a" }); //false
Console.WriteLine(new { A = 1, B = "a" }.Equals(new { A = 1, B = "a" })); //true
答案 1 :(得分:1)
GroupBy
使用标准哈希+等于方法(与Hashtable
,Dictionary<,>
等相同),也就是说:
GetHashCode
定义明确的不相等(当不同时)和可能的相等(当相同时)IEquatable<T>.Equals
或object.Equals
)定义相等您的投影组比较ParentName
,因此在比较项目时使用。由于string
定义明确GetHashCode
/ Equals
,因此效果很好。
回答你的最后一个问题:
我想,新的通过源集合在每次迭代中创建新对象。
严格地说,是的。但它只列举一次,所以这不是问题。即使它没有,匿名类型new {...}
本身也有基于组件成员的相等定义。
答案 2 :(得分:0)
它不会调用==
运算符。
它询问EqualityComparer<T>.Default
实例是否相等。
反过来,它会在Equals
实施中调用IEquatable
,如果有,或Object.Equals
方法作为最后的手段。
Equals
的默认实现支持引用类型的引用相等,以及值类型的按位相等。
但是,如果您需要设置自己的相等规则,则可以自由覆盖该方法。
在您的示例中,parent
如果是匿名类型。 C#编译器生成逐字段Equals
和GetHashCode
实现,因为显然您无法自己提供它们。
答案 3 :(得分:0)
每个.Net对象都实现IComparer接口,并拥有自己的CompareTo方法实现。 .Net只是使用这种方法来确定某些东西是否相等,在这种情况下.net只是检查两个对象的公共属性是否具有相同的值,因此它们是相等的。
编辑:抱歉,我把IComparer CompareTo与object.Equals混淆,每个对象实现了Equals方法,作为一个例子,String类重写了这个方法,只是检查两个字符串是否包含相同的值而不是引用相同的内存地址。答案 4 :(得分:0)
要覆盖.Net的默认比较行为,您应该执行以下操作:
class A
{
public long ParentId;
public string ParentName;
public string Name;
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
if (obj.GetType() != typeof(A))
return false;
var other=(A) obj;
return Equals(other.ParentId, ParentId) && Equals(other.ParentName, ParentName);
}
public override int GetHashCode()
{
unchecked
{
return (ParentName.GetHashCode() * 397) ^ ParentId.GetHashCode();
}
}
}