2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【VB.NET】.NET 10でLINQに追加されたメソッドを使ってみる

Posted at

はじめに

これは、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型を実現させたりすることはできます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?