2011-07-14 8 views
11

Estaba jugando con algunas de las muestras de linq que vienen con LINQPad. En la carpeta "C# 3.0 in a Nutshell", debajo de Chater 9 - Agrupación, hay una consulta de muestra llamada "Agrupación por claves múltiples". Contiene la siguiente consulta:VB.NET grupo linq por tipos anónimos que no funcionan como se esperaba

from n in new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable() 
group n by new 
{ 
    FirstLetter = n[0], 
    Length = n.Length 
} 

añadí la cadena "Jon" al final de la matriz para obtener una agrupación real, y se acercó con el siguiente resultado:

C# LINQPad result

Este era exactamente lo que esperaba. Luego, en LINQPad, fui a la versión VB.NET de la misma consulta:

' Manually added "Jon" 
from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _ 
group by ng = new with _ 
{ _ 
    .FirstLetter = n(0), _ 
    .Length = n.Length _ 
} into group 

el resultado no adecuadamente grupo Jay/Jon juntos.

VB.NET LINQPad result

Después de tirar de mi pelo un poco, descubrí this MSDN article discutir VB.NET tipos anónimos. En VB.NET son mutables por defecto en lugar de C# donde son inmutables. En VB, debe agregar la palabra clave Key para que sean inmutables. Por lo tanto, he cambiado la consulta a este (nótese la adición de Key):

from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _ 
group by ng = new with _ 
{ _ 
    Key .FirstLetter = n(0), _ 
    Key .Length = n.Length _ 
} into group 

Esto me dio el resultado correcto:

enter image description here

Así que mi pregunta es la siguiente:

  1. ¿Por qué la mutabilidad/inmutabilidad de los tipos anónimos importa cuando linq hace una comparación de igualdad? Notablemente, en Linq-to-SQL no importa en absoluto, que probablemente sea solo un producto de la traducción a SQL. Pero en Linq-to-objects aparentemente hace toda la diferencia.
  2. ¿Por qué MS habría decidido convertir los tipos anónimos de VB en modificables? No veo ninguna ventaja real, y después de perder el tiempo con este problema, veo algunas desventajas muy reales. A saber, sus consultas linq pueden tener errores sutiles.

- EDITAR -

Sólo una pieza adicional de información interesante tema de la propiedad ... Al parecer esto se teclea es ampliamente conocido. Simplemente no sabía para qué buscar Google. Se ha discutido here y here en stackoverflow. He aquí otro ejemplo de la cuestión utilizando los tipos anónimos y distintas:

Dim items = New String() {"a", "b", "b", "c", "c", "c"} 
Dim result = items.Select(Function(x) New With {.MyValue = x}).Distinct() 
Dim result2 = items.Select(Function(x) New With {Key .MyValue = x}).Distinct() 
'Debug.Assert(result.Count() = 3) ' Nope... it's 6! 
Debug.Assert(result2.Count() = 3) 
+1

¡Gracias! He estado trabajando alrededor de este problema por más de un año, y todo mi código de Agrupación está bastardeado para arreglar esta rareza. Acabo de tomar una muestra para demostrar este problema y tratar de encontrar una cura, pero esta parece ser la solución. Agregar la palabra clave 'clave' es la solución. He puesto el código en pastebin aquí: http://pastebin.com/pa7KjZv2 – Tom

Respuesta

11

El modificador Key no sólo afecta a la mutabilidad - sino que también afecta el comportamiento de Equals y GetHashCode. Solo las propiedades Key están incluidas en esos cálculos ... lo cual afecta claramente a la agrupación, etc.

En cuanto a por qué es diferente para VB - No lo sé. A mí también me parece extraño. Sé Estoy contento de que C# funciona de la manera que lo hace :) Si bien podría argumentarse que hacer propiedades opcionalmente mutable tiene sentido, no veo por qué debería ser el predeterminado.

Cuestiones relacionadas