我在C#中有以下课程,我试图找到一个独特的项目列表。 该清单有24个要素。
public enum DbObjectType
{
Unknown,
Procedure,
Function,
View
}
public class DbObject
{
public string DatabaseName { get; set; }
public string SchemaName { get; set; }
public string ObjectName { get; set; }
public DbObjectType ObjectType { get; set; }
}
我有两种方法并希望得到相同的结果,但我不会。
第一个表达式返回相同的列表(包括重复项)
var lst1 = from c in DependantObject
group c by new DbObject
{
DatabaseName = c.DatabaseName,
SchemaName = c.SchemaName,
ObjectName = c.ObjectName,
ObjectType = c.ObjectType
} into grp
select grp.First();
lst1将有24个项目。
但是这个会返回所需的结果。
var lst2 = from c in DependantObject
group c by new
{
DatabaseName = c.DatabaseName,
SchemaName = c.SchemaName,
ObjectName = c.ObjectName,
ObjectType = c.ObjectType
} into grp
select grp.First();
lst2将有10个项目。
唯一的区别是第二个表达式是匿名的,但第一个表达式是键入的。
我有兴趣了解这种行为。
谢谢!
我相信我的问题与上述问题不重复,因为: 我在这里问的不是如何获得不同的清单。我问为什么Typed和Anonymous数据会返回不同的结果。
答案 0 :(得分:2)
Linq的Distinct()
方法需要覆盖GetHashCode
和Equals
。
C#的anoynmous类型(new { Name = value }
语法)会创建覆盖这些方法的类,但您自己的DbObject
类型却没有。
您也可以创建自定义IEqualityComparer
类型。看看StructuralComparisons.StructuralEqualityComparer
。
选项1:
public class DbObject : IEquatable<DbObject> {
public override Int32 GetHashCode() {
// See https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
unchecked
{
int hash = 17;
hash = hash * 23 + this.DatabaseName.GetHashCode();
hash = hash * 23 + this.SchemaName.GetHashCode();
hash = hash * 23 + this.ObjectName.GetHashCode();
hash = hash * 23 + this.ObjectType.GetHashCode();
return hash;
}
}
public override Boolean Equals(Object other) {
return this.Equals( other as DbObject );
}
public Boolean Equals(DbObject other) {
if( other == null ) return false;
return
this.DatabaseName.Equals( other.DatabaseName ) &&
this.SchemaName.Equals( other.SchemaName) &&
this.ObjectName.Equals( other.ObjectName ) &&
this.ObjectType.Equals( other.ObjectType);
}
}
选项2:
class DbObjectComparer : IEqualityComparer {
public Boolean Equals(DbObject x, DbObject y) {
if( Object.ReferenceEquals( x, y ) ) return true;
if( (x == null) != (y == null) ) return false;
if( x == null && y == null ) return true;
return
x.DatabaseName.Equals( y.DatabaseName ) &&
x.SchemaName.Equals( y.SchemaName) &&
x.ObjectName.Equals( y.ObjectName ) &&
x.ObjectType.Equals( y.ObjectType);
}
public override Int32 GetHashCode(DbObject obj) {
unchecked
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + obj.DatabaseName.GetHashCode();
hash = hash * 23 + obj.SchemaName.GetHashCode();
hash = hash * 23 + obj.ObjectName.GetHashCode();
hash = hash * 23 + obj.ObjectType.GetHashCode();
return hash;
}
}
}
选项2用法:
var query = this.DependantObject
.GroupBy( c => new DbObject() {
DatabaseName = c.DatabaseName,
SchemaName = c.SchemaName,
ObjectName = c.ObjectName,
ObjectType = c.ObjectType
} )
.First();
使用GroupBy
可能不是最理想的,您可以直接使用Linq Distinct
:
var query = this.DependantObject
.Select( c => new DbObject() {
DatabaseName = c.DatabaseName,
SchemaName = c.SchemaName,
ObjectName = c.ObjectName,
ObjectType = c.ObjectType
} )
.Distinct()
.First();