在使用linq distinct集合的时候,匿名对象和非匿名对象的区别非常有趣。 匿名对象自动实现了GetHashCode和Equals方法,Distinct可以自动去重。
如果使用非匿名对象,则需要该类override GetHashCode()和Equals(object obj)方法, 或者添加一个实现IEqualityComparer<T>的辅助类,作为Distinct参数。
参考下面的例子:
#region anonymous object
var anonymousObj1 = new
{
Time1 = new DateTime(2016, 10, 1),
Time2 = new DateTime(2016, 10, 2)
};
var anonymousObj2 = new
{
Time1 = new DateTime(2016, 10, 1),
Time2 = new DateTime(2016, 10, 2)
};
Trace.WriteLine(anonymousObj1 == anonymousObj2); // false
Trace.WriteLine(Object.ReferenceEquals(anonymousObj1, anonymousObj2)); // false
Trace.WriteLine(anonymousObj1.GetHashCode() == anonymousObj2.GetHashCode()); // true
Trace.WriteLine(anonymousObj1.Equals(anonymousObj2)); // true
#endregion
#region non-anonymous object
var classObj1 = new Class1
{
Time1 = new DateTime(2016, 10, 1),
Time2 = new DateTime(2016, 10, 2)
};
var classObj2 = new Class1
{
Time1 = new DateTime(2016, 10, 1),
Time2 = new DateTime(2016, 10, 2)
};
Trace.WriteLine(classObj1 == classObj2); // false
Trace.WriteLine(Object.ReferenceEquals(classObj1, classObj2)); // false
Trace.WriteLine(classObj1.GetHashCode() == classObj2.GetHashCode()); // false
Trace.WriteLine(classObj1.Equals(classObj2)); // false
#endregion
// distinct
IList<Class1> list = new List<Class1>()
{
new Class1() {SerialNo =1, Time1 = new DateTime(2016, 10, 1), Time2 = new DateTime(2017, 10, 1) },
new Class1() {SerialNo =1, Time1 = new DateTime(2016, 10, 1), Time2 = new DateTime(2017, 10, 1) },
new Class1() {SerialNo =1, Time1 = new DateTime(2016, 10, 3), Time2 = new DateTime(2017, 10, 10) },
new Class1() {SerialNo =1, Time1 = new DateTime(2016, 10, 4), Time2 = new DateTime(2017, 10, 10) }
};
// Count: 4. Class1 must overide GetHashCode and Equals method.
var result1 = list.Select(p => new Class1 { Time1 = p.Time1, Time2 = p.Time2 }).Distinct();
// Count: 3.
var result2 = list.Select(p => new { Time1 = p.Time1, Time2 = p.Time2 }).Distinct();