Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Вы расширяете набор методов, используемых для запросов LINQ, добавив методы расширения в IEnumerable<T> интерфейс. Например, помимо стандартных средних или максимальных операций, вы создадите пользовательский агрегатный метод для вычисления одного значения из последовательности значений. Вы также создаете метод, который работает в качестве пользовательского фильтра или определенного преобразования данных для последовательности значений и возвращает новую последовательность. Примерами таких методов являются Distinct, Skipи Reverse.
При расширении IEnumerable<T> интерфейса можно применить пользовательские методы к любой перечисленной коллекции. Дополнительные сведения см. в статье Методы расширения.
Добавление агрегатного метода
Агрегатный метод вычисляет одно значение из набора значений. LINQ предоставляет несколько агрегатных методов, в том числе Average, Minи Max. Вы можете создать собственный агрегатный метод, добавив метод расширения в IEnumerable<T> интерфейс.
В следующем примере кода показано, как создать метод расширения, вызываемый Median
для вычисления медиана для последовательности чисел типа 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
Этот метод расширения вызывается для любой перечисленной коллекции так же, как и вызов других агрегатных методов из IEnumerable<T> интерфейса.
Замечание
В Visual Basic можно использовать вызов метода или стандартный синтаксис запроса для Aggregate
предложения или Group By
предложения. Дополнительные сведения см. в агрегатном предложении и предложении GROUP BY.
В следующем примере кода показано, как использовать Median
метод для массива типов 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
Перегрузка метода агрегирования для принятия различных типов
Вы можете перегрузить агрегатный метод, чтобы он принимал последовательности различных типов. Стандартный подход заключается в создании перегрузки для каждого типа. Другой подход заключается в создании перегрузки, которая будет принимать универсальный тип и преобразовывать его в конкретный тип с помощью делегата. Вы также можете объединить оба подхода.
Создать перегрузку для каждого типа
Вы можете создать определенную перегрузку для каждого типа, который требуется поддерживать. В следующем примере кода показана перегрузка метода Median
для типа integer
.
' 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
Теперь можно вызвать Median
перегрузки для обоих типов integer
и double
, как показано в следующем коде.
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
Создание универсальной перегрузки
Можно также создать перегрузку, которая принимает последовательность универсальных объектов. Эта перегрузка принимает делегат в качестве параметра и использует его для преобразования последовательности объектов универсального типа в конкретный тип.
В следующем коде показана перегрузка метода Median
, который принимает делегат Func<T,TResult> в качестве параметра. Этот делегат принимает объект универсального типа T
и возвращает объект типа 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
Теперь можно вызвать Median
метод для последовательности объектов любого типа. Если тип не имеет собственной перегрузки метода, необходимо передать параметр делегата. В Visual Basic для этой цели можно использовать лямбда-выражение. Кроме того, если вместо вызова метода используется предложение Aggregate
или Group By
, можно передать любое значение или выражение, которое находится в области действия этого предложения.
В следующем примере кода показано, как вызвать Median
метод для массива целых чисел и массив строк. Для строк вычисляется медиана длины строк в массиве. В примере показано, как передать параметр делегата Func<T,TResult> методу Median
для каждого случая.
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
Добавление метода, возвращающего коллекцию
Интерфейс можно расширить IEnumerable<T> с помощью пользовательского метода запроса, который возвращает последовательность значений. В этом случае метод должен возвращать коллекцию типов IEnumerable<T>. Такие методы можно использовать для применения фильтров или преобразований данных к последовательности значений.
В следующем примере показано, как создать метод расширения с именем AlternateElements
, который возвращает каждый другой элемент в коллекции, начиная с первого элемента.
' 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
Этот метод расширения можно вызвать для любой перечисленной коллекции так же, как и для вызова других методов из IEnumerable<T> интерфейса, как показано в следующем коде:
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