2011-07-02 14 views
7

Przypuśćmy na odpowiednie List poniżej zawiera 2 elementy:Wyraźne w LINQ z anonimowych typów (w VB.NET)

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

powyższy kod zwraca

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

Jak mogę uzyskać różne wartości? Zapytanie Countries powinna zawierać tylko

.Country=Spain .CountryID = 1 
+0

Okazało się to być ciekawe pytanie Chocol8. – Khepri

Odpowiedz

32

Mogę tylko założyć, że nie żyjesz z powodu użycia anonimowego typu, ponieważ odpowiedź udzielona przez Alexa Pecka jest prawidłowa. (i przegłosowałem to).

To jednak sprowadza się do dyskusji na temat kompilatora VB.NET i C#.

W VB.NET, gdy napotkany zostanie typ anonimowy, do celów porównawczych można użyć tylko tych właściwości zadeklarowanych jako właściwości klucza. Tak więc w VB.NET bez klucza, gdy próbujesz dokonać wyraźnego porównania, nic się nie wydarzy.

Read all about it here.

Więc po pierwsze, aby odpowiedzieć na to pytanie, to działa z anonimowych typy:

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

enter image description here

Dlatego odpowiedź freedompeace za nie do końca pracy.

C# jednak kompilator jest trochę inny.

Gdy napotkany zostanie typ anonimowy i konieczna jest operacja porównania, kompilator C# przesłania wartości Equals i GetHashCode. Zostanie powtórzone we wszystkich publicznych właściwościach anonimowego typu, aby obliczyć kod skrótu obiektu, aby przetestować równość.

And you can read more about that here.

Nadzieja to odpowiedzi na swoje pytanie.

+0

+1 interesujące, jestem lepiej zorientowany w C# i nie byłem świadomy różnic tutaj. –

+0

@ Khepri To jest świetne! Dzięki! – OrElse

+0

Ważna uwaga z [artykułu MSDN] (http://msdn.microsoft.com/en-us/library/bb384767.aspx): > Właściwości w anonimowym typie tworzonym przez zapytanie są zawsze kluczowymi właściwościami. Zobacz także [niniejszy test] (https://gist.github.com/janv8000/9407469). – janv8000

2

Jest operator LINQ nazwie Wyraźny(), które można nazwać tak:

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

Więcej informacji na wyraźnych here

+0

lonita: To nie działa – OrElse

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

To nie działa – OrElse

5
Dim distinctCountries = Countries.Distinct() 

Działa to dla mnie, gdy zatrzymuję się na ostatniej linii debuggera:

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 To też nie działa. – OrElse

2

Odrębny musi wiedzieć, jakie obiekty są takie same. Wybierasz tutaj obiekty anonimowe, nie wiadomo, które są równe. Nigdy nie napisałem ani jednej linii VB.Netto, ale próbowałem coś, i to działa:

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 

W twoim przypadku:

Dim Countries = From c In List 
       Select c.Country, c.CountryID Distinct 
Powiązane problemy