views:

110

answers:

2

According to the MSDN:

Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashcode of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

However, the following code demonstrates the compiler generated implementation for Equals() isn't behaving as expected.:

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

Am I missing something? I am looking at the generated MSIL but don't see an obvious error. Is there a way for MSIL level debugging (besides WinDbg maybe)? Am I overlooking something?

I have tested .NET 3.5 (VS 2008 SP1 compiler). For reference, here's the generated Equals method:

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));
}
+6  A: 

== is not Equals() - I believe that your code should work as expected when you do this:

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

See also this SO question.

Lucero
+5  A: 

Lucero has it right, but I want to add an explanation of why that's right.

For reference types in .Net, the == operator is meant to indicate reference equality; do two variables refer to the exact same instance of an object?

The .Equals() method, on the other hand, is meant to indicate value equality; do the two (probably) different instances of an object have the same value, for some definition of "same" that you are normally allowed to provide for your types?

Joel Coehoorn
...with the usual exception, the `string` type, which is also compared for value equality when using `==` (in contrast to Java) ;)
Lucero
argh! (slapping my forehead) I forgot about that. OMG.
Johannes Rudolph