2011-11-04 6 views
6

Tengo un problema donde quiero que un tipo de grupo sea fuertemente tipado, pero si lo hago no se agrupa correctamente. Ver el código de abajo ...¿Por qué usar el tipo de trabajo anónimo y usar un tipo explícito no en 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; } 
     } 
    } 
} 

La salida:

1 
3 
Press any key to continue . . . 

que sería de esperar que el resultado sea el mismo, independientemente de la utilización de un tipo explícito ni es decir, no sólo debe haber un grupo con 3 artículos no 3 grupos con 1 artículo ¿Que esta pasando aqui?

actualización que añade un IEqualityComparer y funciona ahora! Ver más abajo:

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

Salida:

1 
1 
Press any key to continue . . . 

Esto confirma más o menos la respuesta dada por JaredPar!

+0

¿Se comporta si cambia los segundos 'grupos' a un nombre de variable diferente y en lugar de usar' 'utiliza a' '? Es posible que la desconexión sea la tipificación genérica en esta instancia. –

+0

@ Joel: de hecho, lo dinámico no pareció marcar la diferencia hasta que agregué IEqualityComparer y me obligó a cambiarlo para que los tipos se alinearan. – Jim

Respuesta

7

En la primera versión está creando un tipo anónimo con una sola propiedad llamada GroupKey. Los tipos anónimos en C# usan la igualdad estructural, por lo que la igualdad de los valores se reduce a la igualdad de las claves. Esto hace que se agrupen adecuadamente.

En el segundo caso está utilizando un tipo personalizado llamado GroupingKey. Parece que esto usa la igualdad predeterminada o referencial. Por lo tanto, ninguna de las instancias se considera igual y, por lo tanto, se ponen en diferentes grupos.

Cuestiones relacionadas