"=="运算符不像编译器生成的Equals()覆盖匿名类型

Joh*_*lph 8 .net c# compiler-construction anonymous-types

根据MSDN:

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

但是,以下代码演示了编译器生成的实现Equals()不符合预期:

 DateTime start = new DateTime(2009,1,1);
 DateTime end = new DateTime(2010, 12,31);

 // months since year 0
 int startMonth = start.Date.Year * 12 + start.Date.Month - 1;
 int endMonth = end.Date.Year * 12 + end.Date.Month -1 ;

 // iterate through month-year pairs
 for (int i = startMonth; i <= endMonth ; i++)
 {
  var yearMonth = new { Year = (int)Math.Truncate(i/12d), Month = (i % 12) + 1};

  if (yearMonth.Year == 2009 &&  yearMonth.Month == 2)
   Console.WriteLine("BOOM");

  if (yearMonth == new{Year = 2009, Month = 2})
   Console.WriteLine("I'm never called!");

  Console.WriteLine(yearMonth);
 }
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?我正在查看生成的MSIL,但没有看到明显的错误.有没有办法进行MSIL级调试(除了WinDbg)?我忽略了什么吗?

我测试过.NET 3.5(VS 2008 SP1编译器).作为参考,这是生成的Equals方法:

public override bool Equals(object value)
{
    var type = value as <>f__AnonymousType3<<Year>j__TPar, <Month>j__TPar>;
    return (((type != null) && EqualityComparer<<Year>j__TPar>.Default.Equals(this.<Year>i__Field, type.<Year>i__Field)) && EqualityComparer<<Month>j__TPar>.Default.Equals(this.<Month>i__Field, type.<Month>i__Field));
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*ero 7

==不是Equals()- 我相信你的代码应该按预期工作:

if (yearMonth.Equals(new{Year = 2009, Month = 2}))
Run Code Online (Sandbox Code Playgroud)

另见这个问题.


Joe*_*orn 6

Lucero说得对,但我想补充说明为什么这是正确的.

对于.Net中的引用类型,==运算符用于表示引用相等; 两个变量是指一个对象的完全相同的实例?

另一方面,.Equals()方法用于表示相等; 两个(可能)对象的不同实例是否具有相同的值,对于您通常允许为您的类型提供的"相同"的某些定义?

  • ...除了通常的例外,`string`类型,当使用`==`时也比较值相等(与Java相比);) (3认同)