2011-11-04 3 views
6

Ho un problema in cui voglio che un tipo di gruppo sia fortemente digitato, ma se lo faccio non raggruppa correttamente. Vedere il codice qui sotto ...Perché usare il tipo anonimo funziona e usa un tipo esplicito non in un GroupBy?

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication35 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Foo> foos = new List<Foo>(); 
      foos.Add(new Foo() { Key = "Test" }); 
      foos.Add(new Foo() { Key = "Test" }); 
      foos.Add(new Foo() { Key = "Test" }); 

      var groups = foos.GroupBy<Foo, dynamic>(entry => new 
      { 
       GroupKey = entry.Key 
      }); 

      Console.WriteLine(groups.Count()); 

      groups = foos.GroupBy<Foo, dynamic>(entry => new GroupingKey() 
      { 
       GroupKey = entry.Key 
      }); 

      Console.WriteLine(groups.Count()); 

     } 

     public class Foo 
     { 
      public string Key { get; set; } 
     } 

     public class GroupingKey 
     { 
      public string GroupKey { get; set; } 
     } 
    } 
} 

L'output:

1 
3 
Press any key to continue . . . 

mi aspetterei che il risultato sia lo stesso indipendentemente utilizzando un tipo esplicito né cioè non dovrebbe essere solo un gruppo con 3 elementi non 3 gruppi con 1 oggetto. Che cosa sta succedendo qui?

Aggiornamento ho aggiunto un IEqualityComparer e funziona ora! Vedere di seguito:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication35 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Foo> foos = new List<Foo>(); 
      foos.Add(new Foo() { Key = "Test" }); 
      foos.Add(new Foo() { Key = "Test" }); 
      foos.Add(new Foo() { Key = "Test" }); 

      var groups = foos.GroupBy<Foo, dynamic>(entry => new //GroupingKey() 
      { 
       GroupKey = entry.Key 
      }); 

      Console.WriteLine(groups.Count()); 

      groups = foos.GroupBy<Foo, GroupingKey>(entry => new GroupingKey() 
      { 
       GroupKey = entry.Key 
      }, new GroupingKeyEqualityComparer()); 

      Console.WriteLine(groups.Count()); 

     } 

     public class Foo 
     { 
      public string Key { get; set; } 
     } 

     public class GroupingKey 
     { 
      public string GroupKey { get; set; }    
     } 

     public class GroupingKeyEqualityComparer : IEqualityComparer<GroupingKey> 
     { 
      #region IEqualityComparer<GroupingKey> Members 

      public bool Equals(GroupingKey x, GroupingKey y) 
      { 
       return x.GroupKey == y.GroupKey; 
      } 

      public int GetHashCode(GroupingKey obj) 
      { 
       return obj.GroupKey.GetHashCode(); 
      } 

      #endregion 
     } 
    } 
} 

uscita:

1 
1 
Press any key to continue . . . 

Questo più o meno conferma la risposta data da JaredPar!

+0

Si comporta se si modifica il secondo 'gruppi 'in un nome di variabile diverso e invece di usare' 'usa un' '? È possibile che la disconnessione sia la tipizzazione generica in questa istanza. –

+0

@Joel: in realtà la cosa dinamica non sembrava fare la differenza finché non ho aggiunto IEqualityComparer e mi ha costretto a modificarlo in modo che i tipi fossero allineati. – Jim

risposta

7

Nella prima versione si sta creando un tipo anonimo con una singola proprietà denominata GroupKey. I tipi anonimi in C# usano l'uguaglianza strutturale così l'uguaglianza dei valori scende all'eguaglianza delle chiavi. Questo fa sì che siano correttamente raggruppati.

Nel secondo caso si utilizza un tipo personalizzato denominato GroupingKey. Sembra che questo usi l'uguaglianza di default o referenziale. Quindi nessuna delle istanze è considerata uguale e quindi vengono messe in gruppi diversi.