2011-07-02 11 views
7

Suponiendo que los que se hace referencia List siguiente contiene 2 elementos:distinto en LINQ con los tipos anónimos (en VB.NET)

Dim Countries = From c In List _ 
       Select New With { .Country = c.Country, .CountryID = c.CountryID } 

el código anterior devuelve

.Country=Spain .CountryID = 1 
.Country=Spain .CountryID = 1 

¿Cómo puedo obtener los valores distintos? La consulta Countries debe contener solamente

.Country=Spain .CountryID = 1 
+0

Esto resultó ser una cuestión interesante Chocol8. – Khepri

Respuesta

32

Solo puedo suponer que está completamente equivocado en el uso del tipo anónimo ya que la respuesta dada por Alex Peck es correcta. (y lo he subido)

Sin embargo, esto se reduce a una discusión del compilador VB.NET vs C#.

En VB.NET, cuando se encuentra un tipo anónimo, solo se pueden utilizar las propiedades declaradas como propiedades clave para fines de comparación. Entonces, en VB.NET sin clave, cuando intenta hacer una comparación clara, no ocurrirá nada.

Read all about it here.

Así que, primero, para responder a su pregunta, esto funciona con tipos anónimos:

Dim Countries = From c In List Select New With {Key c.CountryId, c.Country} Distinct.ToList 

enter image description here

Esta es la razón por la respuesta de freedompeace no funciona bien.

C# sin embargo, el compilador es un poco diferente.

Cuando se encuentra un tipo anónimo y se necesita una operación de comparación, el compilador C# anula Equals y GetHashCode. Se iterará sobre todas las propiedades públicas del tipo anónimo para calcular el código hash del objeto para probar la igualdad.

And you can read more about that here.

la esperanza que esto responda a su pregunta.

+0

+1 interesante, estoy mejor versado en C# y no estaba al tanto de las diferencias aquí. –

+0

@Khepri ¡Eso es genial! ¡Gracias! – OrElse

+0

Nota importante del [artículo de MSDN] (http://msdn.microsoft.com/en-us/library/bb384767.aspx): > Las propiedades en un tipo anónimo creadas por una consulta son siempre propiedades clave. Ver también [este caso de prueba] (https://gist.github.com/janv8000/9407469). – janv8000

2

No es el operador LINQ nombre distinto(), que se puede llamar así:

Dim Countries = (From c In List _ 
      Select c.Country, c.CountryID).Distinct() 

Más información sobre Distinto here

+0

lonita: Esto no funciona – OrElse

1
Dim Countries = From c In List _ 
       Select New With {.Country = c.Country, .CountryID = c.CountryID }.Distinct() 
+0

Esto no funciona – OrElse

5
Dim distinctCountries = Countries.Distinct() 

Esto funciona para mí cuando paro en la última línea del depurador:

Imports System.Text 

<TestClass()> 
Public Class UnitTest1 

    Class Test 
     Public Country As String 
     Public CountryID As Integer 
    End Class 

    <TestMethod()> 
    Public Sub TestMethod1() 

     Dim List(1) As Test 
     List(0) = New Test With {.Country = "Spain", .CountryID = 1} 
     List(1) = New Test With {.Country = "Spain", .CountryID = 1} 

     Dim Countries = From c In List Select c.Country, c.CountryID 

     Dim distinctCountries = Countries.Distinct() 
    End Sub 

End Class 
+0

Peck Esto tampoco funciona. – OrElse

2

Distinto debe saber de alguna manera qué objetos son los mismos. Aquí selecciona objetos anónimos, no sabe cuáles son iguales. Nunca escribí una sola línea de VB.Net, pero he intentado algo, y funciona:

Module Module1 

    Sub Main() 
     Dim countries As List(Of Country) = New List(Of Country) 
     Dim spain1 As Country = New Country() 
     Dim spain2 As Country = New Country() 
     Dim spain3 As Country = New Country() 
     Dim hungary As Country = New Country() 
     spain1.ID = 1 
     spain1.Name = "Spain" 
     spain2.ID = 1 
     spain2.Name = "Spain" 
     spain3.ID = 2 
     spain3.Name = "Spain" 
     hungary.ID = 3 
     hungary.Name = "Hungary" 
     countries.Add(spain1) 
     countries.Add(spain2) 
     countries.Add(spain3) 
     countries.Add(hungary) 

     Dim ctr = From c In countries Select c.Name, c.ID 
        Distinct 

     For Each c In ctr 
      Console.WriteLine(c) 
     Next 
    End Sub 

    Public Class Country 

     Protected _name As String 

     Protected _id As Long 

     Public Property Name() As String 
      Get 
       Return _name 
      End Get 
      Set(ByVal value As String) 
       _name = value 
      End Set 
     End Property 

     Public Property ID() As Long 
      Get 
       Return _id 
      End Get 
      Set(ByVal value As Long) 
       _id = value 
      End Set 
     End Property 

    End Class 
End Module 

En su caso:

Dim Countries = From c In List 
       Select c.Country, c.CountryID Distinct 
Cuestiones relacionadas