Como: adicionar métodos personalizados para consultas LINQ (Visual Basic)
Você pode estender o conjunto de métodos que usa para consultas LINQ adicionando métodos de extensão à interface IEnumerable<T>. Por exemplo, além do padrão médio ou máximo de operações, é possível criar um método de agregação personalizado para calcular um único valor de uma sequência de valores. Também é possível criar um método que funciona como filtro personalizado ou transformação de dados específicos para uma sequência de valores e retorna uma nova sequência. Exemplos desses métodos são Distinct, Skip e Reverse.
Ao estender a interface IEnumerable<T>, você pode aplicar seus métodos personalizados para qualquer coleção enumerável. Para obter mais informações, consulte Métodos de extensão.
Adição de um método de agregação
Um método de agregação calcula um valor único de um conjunto de valores. O LINQ fornece vários métodos de agregação, incluindo Average, Min e Max. Você pode criar seu próprio método de agregação, adicionando um método de extensão à interface IEnumerable<T>.
O exemplo de código a seguir mostra como criar um método de extensão chamado Median
para calcular uma mediana de uma sequência de números do tipo 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
Você chama esse método de extensão para qualquer coleção enumerável da mesma maneira que chama outros métodos de agregação da interface IEnumerable<T>.
Observação
No Visual Basic, você pode usar uma chamada de método ou uma sintaxe de consulta padrão para a cláusula Aggregate
ou Group By
. Para obter mais informações, consulte Cláusula Aggregate e Agrupar por Cláusula.
O exemplo de código a seguir mostra como usar o método Median
para uma matriz do tipo 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
Sobrecarregar um método de agregação para que aceite vários tipos
Você pode sobrecarregar o método de agregação para que ele aceite sequências de vários tipos. A abordagem padrão é criar uma sobrecarga para cada tipo. Outra abordagem é criar uma sobrecarga que vai pegar um tipo genérico e convertê-lo em um tipo específico, usando um delegado. Você também pode combinar as duas abordagens.
Para criar uma sobrecarga para cada tipo
Você pode criar uma sobrecarga específica para cada tipo que deseja oferecer suporte. O exemplo de código a seguir mostra uma sobrecarga do método Median
para o tipo 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
Agora você pode chamar as sobrecargas Median
para os tipos integer
e double
, conforme mostrado no código a seguir:
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
Para criar uma sobrecarga genérica
Você também pode criar uma sobrecarga que aceita uma sequência de objetos genéricos. Essa sobrecarga recebe um delegado como parâmetro e usa-o para converter uma sequência de objetos de um tipo genérico em um tipo específico.
O código a seguir mostra uma sobrecarga do método Median
que recebe o delegado Func<T,TResult> como um parâmetro. Esse delegado recebe um objeto de tipo genérico T
e retorna um objeto do tipo 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
Agora você pode chamar o método Median
para uma sequência de objetos de qualquer tipo. Se o tipo não tem sua própria sobrecarga de método, você precisa passar um parâmetro delegado. No Visual Basic, você pode usar uma expressão lambda com essa finalidade. Além disso, usando a cláusula Aggregate
ou Group By
em vez da chamada de método, você pode passar qualquer valor ou expressão que esteja no escopo dessa cláusula.
O exemplo de código a seguir mostra como chamar o método Median
para uma matriz de inteiros e para uma matriz de cadeias de caracteres. Será calculada a mediana dos comprimentos das cadeias de caracteres na matriz. O exemplo também mostra como passar o parâmetro delegado Func<T,TResult> ao método Median
para cada caso.
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
Adição de um método que retorna uma coleção
Você pode estender a interface IEnumerable<T> com um método de consulta personalizada que retorna uma sequência de valores. Nesse caso, o método deve retornar uma coleção do tipo IEnumerable<T>. Esses métodos podem ser usados para aplicar transformações de dados ou filtros a uma sequência de valores.
O exemplo a seguir mostra como criar um método de extensão chamado AlternateElements
que retorna todos os outros elementos em uma coleção, começando pelo primeiro elemento.
' 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
Você pode chamar esse método de extensão para qualquer coleção enumerável exatamente como chamaria outros métodos da interface IEnumerable<T>, conforme mostrado no código a seguir:
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