Procedimiento para agregar métodos personalizados para las consultas LINQ (Visual Basic)
Para extender el conjunto de métodos que usa para consultas LINQ, agregue métodos de extensión a la interfaz IEnumerable<T>. Por ejemplo, además de las operaciones habituales de promedio o de máximo, puede crear un método de agregación personalizado para calcular un solo valor a partir de una secuencia de valores. También puede crear un método que funcione como un filtro personalizado o como una transformación de datos específica para una secuencia de valores y que devuelva una nueva secuencia. Ejemplos de dichos métodos son Distinct, Skip y Reverse.
Si extiende la interfaz IEnumerable<T>, puede aplicar los métodos personalizados a cualquier colección enumerable. Para obtener más información, vea Métodos de extensión.
Adición de un método de agregación
Un método de agregación calcula un valor único a partir de un conjunto de valores. LINQ proporciona varios métodos de agregación, incluidos Average, Min y Max. Si quiere crear su propio método de agregación, agregue un método de extensión a la interfaz IEnumerable<T>.
En el ejemplo de código siguiente se muestra cómo crear un método de extensión denominado Median
para calcular la mediana de una secuencia de números de 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
Puede llamar a este método de extensión para cualquier colección enumerable de la misma manera en la que llamaría a otros métodos de agregación desde la interfaz IEnumerable<T>.
Nota
En Visual Basic, puede usar una llamada de método o una sintaxis de consulta estándar para la cláusula Aggregate
o Group By
. Para más información, consulte Cláusula Aggregate y Cláusula Group By.
En el ejemplo de código siguiente se muestra cómo usar el método Median
para una matriz de 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
Sobrecargar un método de agregación para que acepte varios tipos
Puede sobrecargar el método de agregación para que acepte secuencias de varios tipos. El enfoque estándar consiste en crear una sobrecarga para cada tipo. Otro enfoque consiste en crear una sobrecarga que tome un tipo genérico y lo convierta a un tipo específico mediante un delegado. También puede combinar ambos enfoques.
Para crear una sobrecarga para cada tipo
Puede crear una sobrecarga específica para cada tipo que desee admitir. En el siguiente ejemplo de código se muestra una sobrecarga del método Median
para el 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
Ahora puede llamar a las sobrecargas Median
para los tipos integer
y double
, como se muestra en el código siguiente:
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 crear una sobrecarga genérica
También puede crear una sobrecarga que acepte una secuencia de objetos genéricos. Esta sobrecarga toma un delegado como parámetro y lo usa para convertir una secuencia de objetos de un tipo genérico a un tipo específico.
En el código siguiente se muestra una sobrecarga del método Median
que toma el delegado Func<T,TResult> como parámetro. Este delegado toma un objeto del tipo genérico T
y devuelve un objeto de 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
Ahora puede llamar al método Median
para una secuencia de objetos de cualquier tipo. Si el tipo no tiene su propia sobrecarga de métodos, deberá pasar un parámetro de delegado. En Visual Basic puede usar una expresión lambda para este propósito. Además, si usa la cláusula Aggregate
o Group By
en lugar de la llamada de método, puede pasar cualquier valor o expresión que esté en el ámbito de esta cláusula.
En el ejemplo de código siguiente se muestra cómo llamar al método Median
para una matriz de enteros y una matriz de cadenas. Para las cadenas, se calcula la mediana de las longitudes de las cadenas de la matriz. En el ejemplo se muestra cómo pasar el parámetro del delegado Func<T,TResult> al 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
Agregar un método que devuelva una colección
Puede extender la interfaz IEnumerable<T> con un método de consulta personalizado que devuelve una secuencia de valores. En este caso, el método debe devolver una colección de tipo IEnumerable<T>. Estos métodos se pueden usar para aplicar filtros o transformaciones de datos a una secuencia de valores.
En el ejemplo siguiente se muestra cómo crear un método de extensión denominado AlternateElements
que devuelve los demás elementos de una colección, empezando por el primer 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
Puede llamar a este método de extensión para cualquier colección enumerable de la misma manera en la que llamaría a otros métodos desde la interfaz IEnumerable<T>, como se muestra en el siguiente código:
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