bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] LINQ to Objects を理解する: 基本構文と遅延実行

[C#] LINQ to Objects を理解する: 基本構文と遅延実行

Jun 19, 2026 C# , .NET bucket-sort

前回は、ラムダ式について見ました。

今回からは、LINQ to Objects を整理します。

LINQ は、配列、リスト、辞書などのデータに対して、検索、絞り込み、変換、並べ替え、集計などを統一的に書くための仕組みです。

その中でも LINQ to Objects は、メモリ上にある .NET オブジェクトのコレクションを対象にします。

int[] numbers = { 1, 2, 3, 4, 5, 6 };

IEnumerable<int> evenNumbers = numbers.Where(number => number % 2 == 0);

このように、配列に対して条件を指定し、偶数だけを取り出せます。

LINQ to Objects とは

LINQ は、Language Integrated Query の略です。

日本語にすると、「言語に統合された問い合わせ機能」と考えるとよいでしょう。

LINQ to Objects は、その LINQ を .NET のオブジェクトコレクションに対して使うものです。

対象になる代表例は次のようなものです。

  • 配列
  • List<T>
  • Dictionary<TKey, TValue>
  • HashSet<T>
  • IEnumerable<T> を実装した独自コレクション

たとえば、次のような商品一覧があるとします。

using System;
using System.Collections.Generic;
using System.Linq;

class Product
{
    public string Name { get; }
    public int Price { get; }
    public bool InStock { get; }

    public Product(string name, int price, bool inStock)
    {
        Name = name;
        Price = price;
        InStock = inStock;
    }
}

この商品一覧から、在庫がある商品だけを取り出せます。

List<Product> products = new List<Product>
{
    new Product("ノート", 200, true),
    new Product("キーボード", 4500, true),
    new Product("マウス", 2500, false)
};

IEnumerable<Product> inStockProducts =
    products.Where(product => product.InStock);

foreach (Product product in inStockProducts)
{
    Console.WriteLine(product.Name);
}

実行結果です。

ノート
キーボード

Where は、条件に合う要素だけを残す LINQ メソッドです。

LINQ が解決すること

LINQ を使わない場合、条件に合う要素を取り出すには foreach と if を組み合わせます。

List<Product> result = new List<Product>();

foreach (Product product in products)
{
    if (product.InStock)
    {
        result.Add(product);
    }
}

もちろん、この書き方でも正しく動きます。

しかし、データ処理が複雑になると、次のような処理が積み重なります。

  • 条件で絞り込む
  • 必要な形に変換する
  • 並べ替える
  • 件数を数える
  • 合計を出す
  • 重複を取り除く

LINQ を使うと、これらを「何をしたいか」に近い形で書けます。

List<string> names = products
    .Where(product => product.InStock)
    .OrderBy(product => product.Price)
    .Select(product => product.Name)
    .ToList();

このコードは、次のように読めます。

  1. 在庫がある商品に絞る
  2. 価格順に並べる
  3. 商品名だけを取り出す
  4. リストにする

処理の意図が、コードの流れとして見えやすくなります。

LINQ を使うための using

LINQ の多くのメソッドは、System.Linq 名前空間にあります。

using System.Linq;

Where、Select、OrderBy、Count、ToList などは、Enumerable クラスの拡張メソッドです。

そのため、using System.Linq; がないと、次のようなメソッドを呼び出せません。

numbers.Where(number => number > 0);

LINQ を使うコードでは、まず using System.Linq; を確認するとよいでしょう。

配列に LINQ を適用する

LINQ to Objects は、配列にも使えます。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] numbers = { 10, 3, 7, 20, 1, 15 };

        IEnumerable<int> result = numbers
            .Where(number => number >= 10)
            .OrderBy(number => number);

        foreach (int number in result)
        {
            Console.WriteLine(number);
        }
    }
}

実行結果です。

10
15
20

配列は IEnumerable<T> として列挙できるため、LINQ の対象になります。

クエリ構文

LINQ には、SQL に似たクエリ構文があります。

IEnumerable<int> result =
    from number in numbers
    where number >= 10
    orderby number
    select number;

完全な例です。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        int[] numbers = { 10, 3, 7, 20, 1, 15 };

        IEnumerable<int> result =
            from number in numbers
            where number >= 10
            orderby number
            select number;

        foreach (int number in result)
        {
            Console.WriteLine(number);
        }
    }
}

実行結果です。

10
15
20

from でデータソースから要素を取り出し、where で条件を指定し、orderby で並べ替え、select で結果を選択しています。

メソッド構文

同じ処理は、メソッド構文でも書けます。

IEnumerable<int> result = numbers
    .Where(number => number >= 10)
    .OrderBy(number => number)
    .Select(number => number);

メソッド構文では、Where や OrderBy などの拡張メソッドをつないで書きます。

クエリ構文とメソッド構文は、どちらも LINQ の書き方です。

構文 特徴
クエリ構文 SQL に近く、複雑な問い合わせを読みやすく書ける
メソッド構文 ラムダ式と相性がよく、すべての LINQ メソッドを使いやすい

実務では、メソッド構文を見かけることが多いです。

ただし、join や複数の from を使う場合は、クエリ構文の方が読みやすいこともあります。

暗黙的に型指定されたローカル変数

LINQ の結果は、型が長くなることがあります。

たとえば、Where の結果は IEnumerable<T> です。

IEnumerable<Product> result = products.Where(product => product.InStock);

このような場合、var を使うと簡潔に書けます。

var result = products.Where(product => product.InStock);

var は、型がなくなるわけではありません。コンパイラが右辺から型を推論します。

LINQ では匿名型を扱うこともあるため、var がよく使われます。

var summaries = products.Select(product => new
{
    product.Name,
    TaxIncludedPrice = product.Price * 1.1
});

このような匿名型には明示的な型名がないため、var が必要になります。

オブジェクト初期化子とコレクション初期化子

LINQ のサンプルでは、オブジェクト初期化子やコレクション初期化子もよく使います。

class Customer
{
    public string Name { get; set; } = "";
    public int Age { get; set; }
}
List<Customer> customers = new List<Customer>
{
    new Customer { Name = "Alice", Age = 30 },
    new Customer { Name = "Bob", Age = 22 },
    new Customer { Name = "Carol", Age = 41 }
};

このようにデータを短く用意できると、LINQ の処理部分に集中できます。

var adults = customers.Where(customer => customer.Age >= 30);

LINQ そのものではありませんが、LINQ と一緒によく使う C# 構文です。

拡張メソッドとしての LINQ

LINQ の Where や Select は、コレクション型そのものに定義されているメソッドではありません。

多くは System.Linq.Enumerable クラスにある拡張メソッドです。

次の 2 つは、ほぼ同じ意味です。

var result1 = numbers.Where(number => number >= 10);

var result2 = Enumerable.Where(numbers, number => number >= 10);

通常は、拡張メソッド構文で書きます。

numbers.Where(number => number >= 10)

この書き方により、配列やリストに直接 Where が生えているように見えます。

遅延実行

LINQ を理解するうえで重要なのが、遅延実行です。

多くの LINQ メソッドは、クエリを作った時点では実行されません。
実際に列挙されたときに実行されます。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3 };

        var query = numbers.Where(number =>
        {
            Console.WriteLine($"判定: {number}");
            return number >= 2;
        });

        Console.WriteLine("クエリを作成しました");

        foreach (int number in query)
        {
            Console.WriteLine($"結果: {number}");
        }
    }
}

実行結果です。

クエリを作成しました
判定: 1
判定: 2
結果: 2
判定: 3
結果: 3

Where を呼んだ時点では、まだ判定処理は実行されていません。

foreach で列挙されたタイミングで、初めて処理が動きます。

遅延実行で結果が変わる例

遅延実行では、クエリを作ったあとに元データを変更すると、列挙時のデータが反映されます。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3 };

        var query = numbers.Where(number => number >= 2);

        numbers.Add(4);

        foreach (int number in query)
        {
            Console.WriteLine(number);
        }
    }
}

実行結果です。

2
3
4

query を作った時点では 4 はありませんでした。

しかし、列挙する前に numbers.Add(4) しているため、結果に 4 が含まれます。

これは便利なこともありますが、意図しない結果になることもあります。

即時実行

LINQ の結果をその場で確定したい場合は、ToList() や ToArray() を使います。

List<int> result = numbers
    .Where(number => number >= 2)
    .ToList();

ToList() を呼んだ時点でクエリが実行され、結果がリストとして確定します。

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3 };

        List<int> result = numbers
            .Where(number => number >= 2)
            .ToList();

        numbers.Add(4);

        foreach (int number in result)
        {
            Console.WriteLine(number);
        }
    }
}

実行結果です。

2
3

ToList() の時点で結果が確定しているため、その後に追加した 4 は含まれません。

LINQ クエリの結果を返す

メソッドから LINQ の結果を返す場合、遅延実行のまま返すか、即時実行して返すかを意識します。

static IEnumerable<Product> FindInStockProducts(IEnumerable<Product> products)
{
    return products.Where(product => product.InStock);
}

このメソッドは、遅延実行のクエリを返します。

呼び出し側が列挙したタイミングで、実際の処理が動きます。

結果を確定して返したいなら、ToList() を使います。

static List<Product> FindInStockProducts(List<Product> products)
{
    return products
        .Where(product => product.InStock)
        .ToList();
}

どちらが正しいかは状況によります。

戻り値 向いている場面
IEnumerable<T> 呼び出し側に列挙タイミングを任せたい
List<T> 結果をその時点で確定したい
T[] 配列として扱いたい

遅延実行は LINQ の強力な特徴ですが、結果をいつ確定するかを意識することが大切です。

まとめ

LINQ to Objects は、メモリ上の .NET オブジェクトコレクションに対して問い合わせを行う仕組みです。

  • 配列や List<T> など、IEnumerable<T> として列挙できるものに使える
  • Where、Select、OrderBy などは Enumerable の拡張メソッドである
  • クエリ構文とメソッド構文の 2 種類がある
  • LINQ では var、ラムダ式、匿名型、オブジェクト初期化子がよく使われる
  • 多くの LINQ メソッドは遅延実行される
  • ToList() や ToArray() を使うと即時実行して結果を確定できる
  • メソッドから返すときは、遅延実行のまま返すか、結果を確定して返すかを意識する

次回は、LINQ to Objects の中心になるフィルター、射影、並べ替えを見ていきます。

C# .NET LINQ LINQ to Objects IEnumerable 遅延実行
← [C#] ラムダ式を理解する [C#] LINQ to Objects を理解する: フィルター・射影・並べ替え →

Related Posts

  • [C#] LINQ to Objects を理解する: クエリの内部表現 Jun 22, 2026
  • [C#] LINQ to Objects を理解する: ページング・集合演算・集計 Jun 21, 2026
  • [C#] LINQ to Objects を理解する: フィルター・射影・並べ替え Jun 20, 2026
  • [C#] 匿名型(Anonymous Types)の使い方 Jun 8, 2026

Table of Contents

  • LINQ to Objects とは
  • LINQ が解決すること
  • LINQ を使うための using
  • 配列に LINQ を適用する
  • クエリ構文
  • メソッド構文
  • 暗黙的に型指定されたローカル変数
  • オブジェクト初期化子とコレクション初期化子
  • 拡張メソッドとしての LINQ
  • 遅延実行
  • 遅延実行で結果が変わる例
  • 即時実行
  • LINQ クエリの結果を返す
  • まとめ

Recent Posts

  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] 外部アセンブリを読み込み実行時に型を呼び出す Jul 7, 2026
  • [C#] リフレクションで型の中身を調べる Jul 6, 2026
  • [C#] 型メタデータとリフレクションの基礎を理解する Jul 5, 2026

Categories

  • C#120
  • .NET119
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Diagnostics1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • System.Collections.Generic
  • デリゲート
  • Code Snippet
  • DynamoDB
  • LINQ
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メモリ管理
  • リフレクション
  • DoS
  • Nginx
  • WordPress
  • メタデータ
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • インターフェース
  • オブジェクト指向
  • クラス設計
  • デザインパターン
  • パターンマッチング
  • ポインター
  • 継承
Powered by Hugo & Explore Theme.