はじめに
これは、Visual Basic Advent Calendar 2025の13日目の記事となります。
11月11日に「.NET 10.0」 がリリースされました。
VB.NETは新機能の対応はしない方針ではあるが、記法に関係ない部分は対応します。
.NET 10.0でLINQに追加されたメソッド
.NET 10.0でLINQに追加された各メソッドができるか確認してみました。
- Sequence
- InfiniteSequence
- Shuffle
- LeftJoin
- RightJoin
また、Reverseのオーバーロード追加についても紹介します。
毎年、RyotaMurohoshi さんの記事を参考にしています。
.NET 7でLINQに追加されたメソッドは、.NET 8の記事内に記載しています。
Sequence
Sequenceメソッドは、start、endInclusive、stepを引数にとり、シーケンス(IEnumerable<T>)を生成するメソッドです。
startから始まって、endInclusiveに到達するまで、stepごとに増分した値をとるシーケンスを生成します。
Public Sub SequenceTest()
Dim sequence = Enumerable.Sequence(start:=1, endInclusive:=10, step:=2)
Console.WriteLine(String.Join(", ", sequence))
End Sub
結果
1, 3, 5, 7, 9
InfiniteSequence
InfiniteSequenceメソッドは、startとstepを引数にとり、終了しないシーケンス(IEnumerable<T>)を生成するメソッドです。startから始まって、stepごとに増分した値をとるシーケンスを生成します。
Public Sub InfiniteSequence()
Dim infiniteSequence = Enumerable.InfiniteSequence(start:=0, step:=1)
Console.WriteLine(String.Join(", ", infiniteSequence.Take(5)))
End Sub
実用上はTakeなどと組み合わせることが多そうです。
結果
0, 1, 2, 3, 4
Shuffle
Shuffleメソッドは、要素をランダムに並び替えたシーケンス(IEnumerable<T>)を生成するメソッドです。
呼び出し元のIEnumerableはそのままで、新たに並び替えたIEnumerable<T>を返します。
Public Sub ShuffleTest()
Dim shuffled = {3, 1, 4, 1, 5, 9, 2}.Shuffle()
' 件数表示
Console.WriteLine($"Count = {shuffled.Count()}")
' 並び替えた結果を表示(Assert.Equal の代わり)
Console.WriteLine(String.Join(", ", shuffled.Order()))
End Sub
結果
Count = 7
1, 1, 2, 3, 4, 5, 9
LeftJoinとRightJoin
LeftJoinメソッドは左外部結合を、RightJoinは右外部結合を行うメソッドです。
どちらも2つのシーケンスを一致するキーに基づいて要素を結合・変換し、新しいシーケンスを作成するメソッドです。
LINQでは、初期からJoinメソッドにより内部結合を行うことができました。また、GroupJoinというメソッドもありました。しかしLINQには、.NET 10まで左外部結合を行うメソッドはありませんでした。
Private Class Student
Public Property Id As String
Public Property Name As String
Public Sub New(id As String, name As String)
Me.Id = id
Me.Name = name
End Sub
End Class
Private Class TestScore
Public Property StudentId As String
Public Property Subject As String
Public Property Score As Integer
Public Sub New(studentId As String, subject As String, score As Integer)
Me.StudentId = studentId
Me.Subject = subject
Me.Score = score
End Sub
End Class
Private Class TestResult
Public Property StudentName As String
Public Property Subject As String
Public Property Score As Integer?
Public Sub New(studentName As String, subject As String, score As Integer?)
Me.StudentName = studentName
Me.Subject = subject
Me.Score = score
End Sub
End Class
LeftJoin
Public Sub LeftJoinTest()
Dim students = {
New Student("1", "Taro"),
New Student("2", "Jiro"),
New Student("3", "Saburo")
}
Dim testScores = {
New TestScore("1", "Math", 90),
New TestScore("1", "English", 100),
New TestScore("2", "Math", 60),
New TestScore("4", "Math", 80)
}
Dim results =
students.LeftJoin(
testScores,
Function(student) student.Id,
Function(score) score.StudentId,
Function(student, score)
Return New TestResult(
student.Name,
If(score IsNot Nothing, score.Subject, Nothing),
If(score IsNot Nothing, CType(score.Score, Integer?), Nothing)
)
End Function
)
For Each r In results
Console.WriteLine(
$"Student={r.StudentName}, Subject={r.Subject}, Score={r.Score}"
)
Next
End Sub
結果
Student=Taro, Subject=Math, Score=90
Student=Taro, Subject=English, Score=100
Student=Jiro, Subject=Math, Score=60
Student=Saburo, Subject=, Score=
RightJoin
Public Sub RightJoinTest()
Dim students = {
New Student("1", "Taro"),
New Student("2", "Jiro"),
New Student("3", "Saburo")
}
Dim testScores = {
New TestScore("1", "Math", 90),
New TestScore("1", "English", 100),
New TestScore("2", "Math", 60),
New TestScore("4", "Math", 80)
}
Dim results =
students.RightJoin(
testScores,
Function(student) student.Id,
Function(score) score.StudentId,
Function(student, score)
Return New TestResult(
If(student IsNot Nothing, student.Name, Nothing),
score.Subject,
score.Score
)
End Function
)
For Each r In results
Console.WriteLine(
$"Student={r.StudentName}, Subject={r.Subject}, Score={r.Score}"
)
Next
End Sub
結果
Student=Taro, Subject=Math, Score=90
Student=Taro, Subject=English, Score=100
Student=Jiro, Subject=Math, Score=60
Student=, Subject=Math, Score=80
Reverse
Reverseメソッドに配列専用のオーバーロードが加わりました。これは「新しく何かできるようにするため」ではなく、「互換性を守るため」の追加です。
Public Sub ReverseTest()
Dim arrary = {3, 1, 4, 1, 5, 9, 2}
Dim reversed = arrary.Reverse()
Console.WriteLine(String.Join(", ", reversed))
End Sub
結果
2, 9, 5, 1, 4, 1, 3
最後に
VB.NET は言語による新機能の対応はしない方針(Record型 や fieldキーワードなど)ですが、共通のLINQの新機能には追随しています。
ソースジェネレータ機能を使用することでRecord型を実現させたりすることはできます。