如何在匿名类型上实现Equals和GetHashCode?

帮助说:

匿名类型是直接从对象派生的类类型,不能转换为除object之外的任何类型。 编译器为每个匿名类型提供名称,尽管您的应用程序无法访问它。 从公共语言运行库的角度来看,匿名类型与任何其他引用类型没有区别。

如果程序集中的两个或多个匿名对象初始值设定项指定了具有相同顺序且具有相同名称和类型的属性序列,则编译器会将对象视为相同类型的实例。 它们共享相同的编译器生成的类型信息。

因为匿名类型上的Equals和GetHashCode方法是根据属性的Equals和GetHashCode方法定义的,所以同一匿名类型的两个实例只有在它们的所有属性相等时才相等。

这些都是真的,但是怎么样? 参考源明确地显示了如何比较对象( ReferenceEquals )和“直接从对象派生”的类型不能具有这种特殊行为。 它与ValueTypeEquals行为也不匹配。

那怎么办? 匿名类型如何覆盖Equals()GetHashCode()而没有任何可见的覆盖?

编译器为您生成GetHashCode()Equals()覆盖。 例如,从以下代码:

 class Program { static void Main(string[] args) { var a = new { Text = "foo", Value = 17 }; Console.WriteLine(a); } } 

你可以在编译的.exe中找到生成的匿名类型,其中方法看起来像这样(这是dotPeek的输出……还有ToString() ):

  [DebuggerHidden] public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{ Text = "); stringBuilder.Append((object) this.\u003CText\u003Ei__Field); stringBuilder.Append(", Value = "); stringBuilder.Append((object) this.\u003CValue\u003Ei__Field); stringBuilder.Append(" }"); return ((object) stringBuilder).ToString(); } [DebuggerHidden] public override bool Equals(object value) { var fAnonymousType0 = value as \u003C\u003Ef__AnonymousType0<\u003CText\u003Ej__TPar, \u003CValue\u003Ej__TPar>; return fAnonymousType0 != null && EqualityComparer<\u003CText\u003Ej__TPar>.Default.Equals(this.\u003CText\u003Ei__Field, fAnonymousType0.\u003CText\u003Ei__Field) && EqualityComparer<\u003CValue\u003Ej__TPar>.Default.Equals(this.\u003CValue\u003Ei__Field, fAnonymousType0.\u003CValue\u003Ei__Field); } [DebuggerHidden] public override int GetHashCode() { return -1521134295 * (-1521134295 * 512982588 + EqualityComparer<\u003CText\u003Ej__TPar>.Default.GetHashCode(this.\u003CText\u003Ei__Field)) + EqualityComparer<\u003CValue\u003Ej__TPar>.Default.GetHashCode(this.\u003CValue\u003Ei__Field); } 

相关阅读:
ToString如何在匿名类型上工作?
为什么匿名类型等于实现比较字段?
匿名类型的平等
为什么ValueType.GetHashCode()实现得像?

这些都没有直接解决您的问题,但它们确实提供了一些有关这些覆盖的具体实现的相关见解。