0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.NET 10でLINQに追加されたメソッド

Last updated at Posted at 2025-11-16

概要

2025年11月に.NET 10C# 14がリリースされました。

この投稿では、.NET 10でLINQ to Objectsに追加された

  • Sequence
  • InfiniteSequence
  • Shuffle
  • LeftJoin
  • RightJoin

について紹介します。

また、Reverseのオーバーロード追加についても紹介します。

過去の追加されたLINQメソッドの記事はこちら

Sequence

Sequenceメソッドは、start、endInclusive、stepを引数にとり、シーケンス(IEnumerable<T>)を生成するメソッドです。

startから始まって、endInclusiveに到達するまで、stepごとに増分した値をとるシーケンスを生成します。

[Fact]
public void SequenceTest()
{
    var sequence = Enumerable.Sequence(start: 1, endInclusive: 10, step: 2);
    Assert.Equal([1, 3, 5, 7, 9], sequence);
}

Sequenceメソッドの型パラメーターである「T」の制約は、「System.Numerics.INumber<T>」です。

end"Incusive"(包括的)なので、endIncluiveと同じ値はシーケンスの最後の要素とし含まれます。

[Fact]
public void SequenceTestWithEndExclusive()
{
    var sequence = Enumerable.Sequence(start: 1, endInclusive: 9, step: 2);
    Assert.Equal([1, 3, 5, 7, 9], sequence);
}

startとendIncluiveが同じで、かつstepが0な場合、stepの値を1個だけ持つシーケンスを生成します。

[Fact]
public void SequenceWithSingleValue()
{
    var sequence = Enumerable.Sequence(start: 1, endInclusive: 1, step: 0);
    Assert.Equal([1], sequence);
}

終了しない条件を引数に渡すと、即座にArgumentOutOfRangeExceptionが投げられます。

[Fact]
public void SequenceTestWithArgumentOutOfRangeException()
{
    Assert.Throws<ArgumentOutOfRangeException>(() =>
    {
        Enumerable.Sequence(start: 1, endInclusive: 9, step: -1);
    });
    Assert.Throws<ArgumentOutOfRangeException>(() =>
    {
        Enumerable.Sequence(start: 1, endInclusive: -5, step: 2);
    });
    Assert.Throws<ArgumentOutOfRangeException>(() =>
    {
        Enumerable.Sequence(start: 1, endInclusive: 10, step: 0);
    });
}

似ているメソッドに「Enumerable.Range」があります。Rangeは、初期値startと要素数countを引数にとります。

[Fact]
public void RangeTest()
{
    var sequence = Enumerable.Range(start: 1, count: 4);
    Assert.Equal([1, 2, 3, 4], sequence);
}

Enumerable.SequenceEnumerable.Rangeは、名前付き引数で書かれていないコードを読む際は、都度リファレンスで挙動を確認したいです。(覚えられなさそう。)

    
    [Fact]
    public void SequenceRangeNoNamedArgument()
    {
        // 第二引数は要素数だっけ?終了条件だっけ?
        var sequence = Enumerable.Sequence(3, 5, 1);
        Assert.Equal([3, 4, 5], sequence);

        // 第二引数は要素数だっけ?終了条件だっけ?
        var range = Enumerable.Range(3, 5);
        Assert.Equal([3, 4, 5, 6, 7], range);
    }

InfiniteSequence

InfiniteSequenceメソッドは、startとstepを引数にとり、終了しないシーケンス(IEnumerable<T>)を生成するメソッドです。startから始まって、stepごとに増分した値をとるシーケンスを生成します。

[Fact]
public void InfiniteSequence()
{
    var infiniteSequence = Enumerable.InfiniteSequence(start: 0, step: 1);
    Assert.Equal([0, 1, 2, 3, 4], infiniteSequence.Take(5));
}

実用上はTakeなどと組み合わせることが多そうです。

InfiniteSequenceメソッドの型パラメーターである「T」の制約は、「System.Numerics.IAdditionOperators<T,T,T>」です。

Shuffle

Shuffleメソッドは、要素をランダムに並び替えたシーケンス(IEnumerable<T>)を生成するメソッドです。

呼び出し元のIEnumerable<T>はそのままで、新たに並び替えたIEnumerable<T>を返します。

[Fact]
public void ShuffleTest()
{
    var shuffled = new[] { 3, 1, 4, 1, 5, 9, 2 }.Shuffle();
    Assert.Equal(7, shuffled.Count());
    Assert.Equal([1, 1, 2, 3, 4, 5, 9], shuffled.Order());
}

配列やSpan<T>の中身を入れ替えたい場合(インプレースシャッフルしたい場合)、RandomクラスのShuffleメソッドを使いましょう。

var array = Enumerable.Range(1, 10).ToArray();
Random.Shared.Shuffle(array);

LeftJoinとRightJoin

LeftJoinメソッドは左外部結合を、RightJoinは右外部結合を行うメソッドです。

どちらも2つのシーケンスを一致するキーに基づいて要素を結合・変換し、新しいシーケンスを作成するメソッドです。

LINQでは、初期からJoinメソッドにより内部結合を行うことができました。また、GroupJoinというメソッドもありました。しかしLINQには、.NET 10まで左外部結合を行うメソッドはありませんでした。今までは、公式サイトでも左外部結合をやりたいのであれば、「GroupJoinメソッドとDefaultIfEmptyメソッドを組み合わる」と紹介されていました。

.NET 10からLeftJoinメソッドが登場し、単一のメソッドで実現できます。

次のレコードを使って例を示します。

private record Student(
    string Id,
    string Name
);

private record TestScore(
    string StudentId,
    string Subject,
    int Score
);

private record TestResult(
    string? StudentName,
    string? Subject,
    int? Score
);

LeftJoinを使った左外部結合の例を次に示します。

[Fact]
public void LeftJoinTest()
{
    var students = new Student[]
    {
        new("1", "Taro"),
        new("2", "Jiro"),
        new("3", "Saburo")
    };
    var testScores = new TestScore[]
    {
        new("1", "Math", 90),
        new("1", "English", 100),
        new("2", "Math", 60),
        new("4", "Math", 80)
    };

    var results = students
        .LeftJoin(testScores,
            student => student.Id,
            score => score.StudentId,
            (student, score) => new TestResult(student.Name, score?.Subject, score?.Score)
        );

    Assert.Equal([
        new TestResult("Taro", "Math", 90),
        new TestResult("Taro", "English", 100),
        new TestResult("Jiro", "Math", 60),
        new TestResult("Saburo", null, null)
    ], results);
}

RightJoinを使った右外部結合の例を次に示します。

[Fact]
public void RightJoinTest()
{
    var students = new Student[]
    {
        new("1", "Taro"),
        new("2", "Jiro"),
        new("3", "Saburo")
    };
    var testScores = new TestScore[]
    {
        new("1", "Math", 90),
        new("1", "English", 100),
        new("2", "Math", 60),
        new("4", "Math", 80)
    };

    var results = students
        .RightJoin(testScores,
            student => student.Id,
            score => score.StudentId,
            (student, score) => new TestResult(student?.Name, score.Subject, score.Score)
        );

    Assert.Equal([
        new TestResult("Taro", "Math", 90),
        new TestResult("Taro", "English", 100),
        new TestResult("Jiro", "Math", 60),
        new TestResult(null, "Math", 80)
    ], results);
}

Reverse

Reverseメソッドに配列専用のオーバーロードが加わりました。これは「新しく何かできるようにするため」ではなく、「互換性を守るため」の追加です。

C#には、IEnumerable<T>型の拡張メソッドとして、Reverseというメソッドがもともとありました。

また、Span<T>型の拡張メソッドとしても、Reverseというメソッドもありました。

次のようなReverseメソッドを呼び出しているコードを例に説明します。

var arrary = new[] { 3, 1, 4, 1, 5, 9, 2 };
arrary.Reverse();

C# 13以前では、上記のコードはIEnumerable<T>型の拡張メソッドReverseが呼び出されていました。

ところで、C# 14で「First-class Span Types」が導入されました。

「.NET 10でReverseメソッドに配列専用のオーバーロードが追加されなかった」と仮定します。その場合、上記のコードはC# 14ではSpan<T>型の拡張メソッドReverseが呼び出されることになります。つまり、C# 13以前とC# 14以降で動作が変わってしまうのです。

そのような動作・挙動の変更を防ぎ、互換性を守るために、Reverseメソッドに配列専用のオーバーロードが.NET 10で追加されました。

まとめ

この投稿では、.NET 10で追加されたLINQメソッドを紹介しました。.NET 10プロジェクトで、どんどん活用していきましょう!

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?