LINQ クエリに使用するメソッドのセットを拡張するには、 IEnumerable<T> インターフェイスに拡張メソッドを追加します。 たとえば、標準の平均または最大操作に加えて、値のシーケンスから 1 つの値を計算するカスタム集計メソッドを作成します。 また、値のシーケンスに対してカスタム フィルターまたは特定のデータ変換として機能し、新しいシーケンスを返すメソッドも作成します。 このようなメソッドの例としては、 Distinct、 Skip、 Reverseがあります。
IEnumerable<T> インターフェイスを拡張するときに、任意の列挙可能なコレクションにカスタム メソッドを適用できます。 詳細については、「拡張メソッド」を参照してください。
集計メソッドの追加
集計メソッドは、一連の値から 1 つの値を計算します。 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
句に対してメソッド呼び出しまたは標準クエリ構文を使用できます。 詳細については、「集計句 」および「グループ化句 」を参照してください。
次のコード例は、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
さまざまな型を受け入れるための集計メソッドのオーバーロード
さまざまな型のシーケンスを受け入れるように、集計メソッドをオーバーロードできます。 標準的な方法は、型ごとにオーバーロードを作成することです。 もう 1 つの方法は、ジェネリック型を受け取り、デリゲートを使用して特定の型に変換するオーバーロードを作成することです。 両方の方法を組み合わせることもできます。
型ごとにオーバーロードを作成するには
サポートする型ごとに特定のオーバーロードを作成できます。 次のコード例は、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
こちらも参照ください
.NET