Udostępnij za pośrednictwem


Porady: dodawanie niestandardowych metod dla zapytań LINQ (Visual Basic)

Rozszerzysz zestaw metod używanych dla zapytań LINQ, dodając metody rozszerzenia do interfejsu IEnumerable<T> . Na przykład oprócz standardowej średniej lub maksymalnej operacji można utworzyć niestandardową metodę agregacji, aby obliczyć pojedynczą wartość z sekwencji wartości. Utworzysz również metodę, która działa jako filtr niestandardowy lub konkretna transformacja danych dla sekwencji wartości i zwraca nową sekwencję. Przykłady takich metod to Distinct, Skipi Reverse.

Po rozszerzeniu interfejsu IEnumerable<T> można zastosować metody niestandardowe do dowolnej kolekcji z możliwością wyliczania. Aby uzyskać więcej informacji, zobacz Metody rozszerzeń.

Dodawanie metody agregującej

Metoda agregacji oblicza pojedynczą wartość z zestawu wartości. LINQ udostępnia kilka metod agregacji, w tym Average, Mini Max. Możesz utworzyć własną metodę agregacji, dodając metodę rozszerzenia do interfejsu IEnumerable<T> .

W poniższym przykładzie kodu pokazano, jak utworzyć metodę rozszerzenia o nazwie Median w celu obliczenia mediany dla sekwencji liczb typu double.

Imports System.Runtime.CompilerServices

Module LINQExtension

    ' Extension method for the IEnumerable(of T) interface.
    ' The method accepts only values of the Double type.
    <Extension()>
    Function Median(ByVal source As IEnumerable(Of Double)) As Double
        If Not source.Any() Then
            Throw New InvalidOperationException("Cannot compute median for an empty set.")
        End If

        Dim sortedSource = (From number In source
                            Order By number).ToList()

        Dim itemIndex = sortedSource.Count \ 2

        If sortedSource.Count Mod 2 = 0 Then
            ' Even number of items in list.
            Return (sortedSource(itemIndex) + sortedSource(itemIndex - 1)) / 2
        Else
            ' Odd number of items in list.
            Return sortedSource(itemIndex)
        End If
    End Function
End Module

Ta metoda rozszerzenia jest wywoływana dla dowolnej kolekcji wyliczalnej w taki sam sposób, jak w przypadku wywoływania innych metod agregacji z interfejsu IEnumerable<T> .

Uwaga

W języku Visual Basic można użyć wywołania metody lub standardowej składni zapytania dla klauzuli Aggregate or Group By . Aby uzyskać więcej informacji, zobacz Agregacja klauzuli i Klauzula Grupuj według.

Poniższy przykład kodu pokazuje, jak używać Median metody dla tablicy typu double.

Dim numbers() As Double = {1.9, 2, 8, 4, 5.7, 6, 7.2, 0}

Dim query = Aggregate num In numbers Into Median()

Console.WriteLine("Double: Median = " & query)
' This code produces the following output:
'
' Double: Median = 4.85

Przeciążanie metody agregującej w celu akceptowania różnych typów

Możesz przeciążyć metodę agregacji, aby akceptowała sekwencje różnych typów. Standardowe podejście polega na utworzeniu przeciążenia dla każdego typu. Innym podejściem jest utworzenie przeciążenia, które będzie przyjmować typ ogólny i konwertować go na określony typ przy użyciu delegata. Można również połączyć oba podejścia.

Aby utworzyć przeciążenie dla każdego typu

Można utworzyć określone przeciążenie dla każdego typu, który chcesz obsługiwać. Poniższy przykład kodu przedstawia przeciążenie Median metody dla integer typu.

' Integer overload
<Extension()>
Function Median(ByVal source As IEnumerable(Of Integer)) As Double
    Return Aggregate num In source Select CDbl(num) Into med = Median()
End Function

Teraz można wywołać Median przeciążenia dla typów integer i double , jak pokazano w poniższym kodzie:

Dim numbers1() As Double = {1.9, 2, 8, 4, 5.7, 6, 7.2, 0}

Dim query1 = Aggregate num In numbers1 Into Median()

Console.WriteLine("Double: Median = " & query1)

Dim numbers2() As Integer = {1, 2, 3, 4, 5}

Dim query2 = Aggregate num In numbers2 Into Median()

Console.WriteLine("Integer: Median = " & query2)

' This code produces the following output:
'
' Double: Median = 4.85
' Integer: Median = 3

Aby utworzyć przeciążenie ogólne

Można również utworzyć przeciążenie, które akceptuje sekwencję obiektów ogólnych. To przeciążenie przyjmuje delegata jako parametr i używa go do konwertowania sekwencji obiektów typu ogólnego na określony typ.

Poniższy kod przedstawia przeciążenie Median metody, która przyjmuje delegata Func<T,TResult> jako parametr. Ten delegat przyjmuje obiekt typu T ogólnego i zwraca obiekt typu double.

' Generic overload.
<Extension()>
Function Median(Of T)(ByVal source As IEnumerable(Of T),
                  ByVal selector As Func(Of T, Double)) As Double
    Return Aggregate num In source Select selector(num) Into med = Median()
End Function

Teraz można wywołać metodę Median dla sekwencji obiektów dowolnego typu. Jeśli typ nie ma własnego przeciążenia metody, musisz przekazać parametr delegata. W języku Visual Basic można w tym celu użyć wyrażenia lambda. Ponadto jeśli używasz klauzuli Aggregate or Group By zamiast wywołania metody, możesz przekazać dowolną wartość lub wyrażenie, które znajduje się w zakresie tej klauzuli.

Poniższy przykładowy kod pokazuje, jak wywołać metodę Median dla tablicy liczb całkowitych i tablicy ciągów. W przypadku ciągów obliczana jest mediana długości ciągów w tablicy. W przykładzie pokazano, jak przekazać parametr delegata Func<T,TResult> do Median metody dla każdego przypadku.

Dim numbers3() As Integer = {1, 2, 3, 4, 5}

' You can use num as a parameter for the Median method
' so that the compiler will implicitly convert its value to double.
' If there is no implicit conversion, the compiler will
' display an error message.

Dim query3 = Aggregate num In numbers3 Into Median(num)

Console.WriteLine("Integer: Median = " & query3)

Dim numbers4() As String = {"one", "two", "three", "four", "five"}

' With the generic overload, you can also use numeric properties of objects.

Dim query4 = Aggregate str In numbers4 Into Median(str.Length)

Console.WriteLine("String: Median = " & query4)

' This code produces the following output:
'
' Integer: Median = 3
' String: Median = 4

Dodawanie metody zwracającej kolekcję

Interfejs można rozszerzyć IEnumerable<T> za pomocą niestandardowej metody zapytania, która zwraca sekwencję wartości. W takim przypadku metoda musi zwrócić kolekcję typu IEnumerable<T>. Takie metody mogą służyć do stosowania filtrów lub przekształceń danych do sekwencji wartości.

W poniższym przykładzie pokazano, jak utworzyć metodę rozszerzenia o nazwie AlternateElements , która zwraca każdy inny element w kolekcji, zaczynając od pierwszego elementu.

' Extension method for the IEnumerable(of T) interface.
' The method returns every other element of a sequence.
<Extension()>
Iterator Function AlternateElements(Of T)(
ByVal source As IEnumerable(Of T)
) As IEnumerable(Of T)
    Dim i = 0
    For Each element In source
        If (i Mod 2 = 0) Then
            Yield element
        End If
        i = i + 1
    Next
End Function

Tę metodę rozszerzenia można wywołać dla dowolnej kolekcji wyliczalnej, tak jak wywołasz inne metody z interfejsu IEnumerable<T> , jak pokazano w poniższym kodzie:

Dim strings() As String = {"a", "b", "c", "d", "e"}

Dim query5 = strings.AlternateElements()

For Each element In query5
    Console.WriteLine(element)
Next

' This code produces the following output:
'
' a
' c
' e

Zobacz też