代码之家  ›  专栏  ›  技术社区  ›  Johannes Rudolph

“==”运算符的行为与编译器为匿名类型生成的equals()重写不同

  •  8
  • Johannes Rudolph  · 技术社区  · 15 年前

    根据 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);
     }
    

    我错过什么了吗?我正在查看生成的MSIL,但没有看到明显的错误。有没有一种方法进行MSIL级调试(可能除了windbg)?我忽略了什么吗?

    我已经测试了.NET 3.5(与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));
    }
    
    2 回复  |  直到 15 年前
        1
  •  7
  •   Community CDub    8 年前

    == 不是 Equals() -我相信当您这样做时,您的代码应该按预期工作:

    if (yearMonth.Equals(new{Year = 2009, Month = 2}))
    

    也见 this SO question .

        2
  •  6
  •   Joel Coehoorn    15 年前

    卢塞罗说得对,但我想加一个解释 为什么 这是正确的。

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

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