C# LINQのSelectとは?使い方・Whereとの違い・複数項目の抽出までサンプルコードで解説

はじめに

C#で配列やListのデータを扱うとき、「必要な値だけ取り出したい」「各要素を加工して新しい一覧を作りたい」という場面はよくあります。そこで使う代表的なLINQメソッドがSelectです。

csharp selectや「C# LINQ Select」で調べている人の多くは、Selectが何をするものなのか、Whereとどう違うのか、複数項目を取り出すにはどう書けばよいのかで迷いやすいです。

この記事では、C# LINQのSelectについて、基本構文から実践的な使い方、WhereSelectManyとの違い、よくあるエラーまでサンプルコード付きで解説します。

1. C# LINQのSelectとは?まずは役割を理解しよう

1-1. Selectはコレクションの各要素を「変換・射影」するためのメソッド

C# LINQのSelectは、配列やListなどのコレクションに含まれる各要素を、別の形に変換するためのメソッドです。

たとえば、数値のリストを2倍にしたり、ユーザー一覧から名前だけを取り出したり、商品データから表示用のデータを作ったりできます。

C#
var numbers = new List<int> { 1, 2, 3 };

var doubled = numbers.Select(x => x * 2);

foreach (var number in doubled)
{
Console.WriteLine(number);
}

実行結果は次のようになります。

C#
2
4
6

この例では、1, 2, 3という各要素をx * 2で変換し、2, 4, 6という新しい結果を作っています。

1-2. Selectでできること:値の加工、プロパティ抽出、新しい型への変換

Selectでできることは主に次の3つです。

値を加工する例です。

C#
var prices = new List<int> { 100, 200, 300 };

var taxIncludedPrices = prices.Select(price => price * 1.1);

オブジェクトのプロパティだけを抽出する例です。

C#
var names = users.Select(user => user.Name);

新しい型に変換する例です。

C#
var userDtos = users.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
});

このように、Selectは「元のデータを別の形にする」ときに使います。

1-3. SQLのSELECT文やC#のselect句との違い

Selectという名前から、SQLのSELECT文を連想する人も多いでしょう。

SQLのSELECT文は、データベースのテーブルから列を選択するために使います。

SQL
SELECT Name, Age FROM Users;

一方、C# LINQのSelectは、C#のコレクションに対して要素を変換するメソッドです。

C#
var names = users.Select(user => user.Name);

また、C#にはクエリ構文のselect句もあります。

C#
var names =
from user in users
select user.Name;

これはメソッド構文のSelectとほぼ同じ意味です。

C#
var names = users.Select(user => user.Name);

つまり、C#では次の3つを区別すると理解しやすくなります。

SQLのSELECTはデータベースの列を選ぶもの、LINQのSelectはコレクションの要素を変換するメソッド、クエリ構文のselect句はLINQをSQL風に書くための構文です。

1-4. Selectを使うために必要なusing System.Linq

Selectを使うには、ファイルの先頭にusing System.Linq;が必要です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

Selectが使えない場合は、まずSystem.Linqが読み込まれているか確認しましょう。

.NET 6以降のプロジェクトでは、テンプレートによって暗黙的に読み込まれている場合もありますが、エラーが出る場合は明示的に追加すると安心です。

2. C# LINQ Selectの基本的な使い方

2-1. 配列・Listから値を取り出す基本構文

Selectの基本構文は次の通りです。

C#
コレクション.Select(要素 => 変換後の値)

たとえば、文字列のリストから各文字列の長さを取り出す場合は次のように書きます。

C#
var words = new List<string> { "apple", "banana", "cat" };

var lengths = words.Select(word => word.Length);

foreach (var length in lengths)
{
Console.WriteLine(length);
}

実行結果です。

C#
5
6
3

word => word.Lengthの部分は、「各要素wordを受け取り、そのLengthを返す」という意味です。

2-2. ラムダ式を使ったSelectの書き方

Selectではラムダ式をよく使います。

C#
x => x * 2

これは、「xを受け取り、x * 2を返す」という処理です。

次のコードでは、各数値を10倍に変換しています。

C#
var numbers = new[] { 1, 2, 3, 4 };

var results = numbers.Select(x => x * 10);

foreach (var result in results)
{
Console.WriteLine(result);
}

実行結果です。

C#
10
20
30
40

ラムダ式の左側が元の要素、右側が変換後の値です。

2-3. 数値を計算して新しいリストを作るサンプルコード

Selectの結果をToList()でListに変換すると、加工済みの新しいリストを作れます。

C#
var scores = new List<int> { 70, 80, 90 };

List<int> adjustedScores = scores
.Select(score => score + 5)
.ToList();

foreach (var score in adjustedScores)
{
Console.WriteLine(score);
}

実行結果です。

C#
75
85
95

元のscoresは変更されません。Selectは元のコレクションを直接書き換えるのではなく、変換後の結果を作るためのメソッドです。

2-4. 文字列を加工して抽出するサンプルコード

文字列の加工にもSelectは便利です。

C#
var names = new List<string> { "tanaka", "suzuki", "sato" };

var upperNames = names.Select(name => name.ToUpper()).ToList();

foreach (var name in upperNames)
{
Console.WriteLine(name);
}

実行結果です。

C#
TANAKA
SUZUKI
SATO

表示用に文字列を整形することもできます。

C#
var names = new List<string> { "Tanaka", "Suzuki", "Sato" };

var displayNames = names.Select(name => $"名前: {name}");

foreach (var displayName in displayNames)
{
Console.WriteLine(displayName);
}

実行結果です。

C#
名前: Tanaka
名前: Suzuki
名前: Sato

2-5. Selectの戻り値はIEnumerable<T>になる

Selectの戻り値は基本的にIEnumerable<T>です。

C#
var numbers = new List<int> { 1, 2, 3 };

IEnumerable<int> results = numbers.Select(x => x * 2);

Tの部分は、変換後の型になります。

たとえば、intからstringに変換する場合、戻り値はIEnumerable<string>になります。

C#
var numbers = new List<int> { 1, 2, 3 };

IEnumerable<string> texts = numbers.Select(x => $"No.{x}");

Listとして扱いたい場合は、最後にToList()を付けます。

C#
List<string> textList = numbers
.Select(x => $"No.{x}")
.ToList();

3. Selectでオブジェクトのプロパティを抽出する方法

3-1. List<User>からNameだけを抽出する

実務でよく使うのが、オブジェクトのリストから特定のプロパティだけを取り出す使い方です。

C#
public class User
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
}

ユーザー一覧からNameだけを抽出します。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka", Age = 25 },
new User { Id = 2, Name = "Suzuki", Age = 30 },
new User { Id = 3, Name = "Sato", Age = 28 }
};

var names = users.Select(user => user.Name);

foreach (var name in names)
{
Console.WriteLine(name);
}

実行結果です。

C#
Tanaka
Suzuki
Sato

usersの各要素はUser型ですが、Select(user => user.Name)によって結果はstringの一覧になります。

3-2. ProductクラスからPriceだけを取り出す

商品クラスから価格だけを取り出す例です。

C#
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
C#
var products = new List<Product>
{
new Product { Id = 1, Name = "Pen", Price = 120m },
new Product { Id = 2, Name = "Notebook", Price = 300m },
new Product { Id = 3, Name = "Bag", Price = 2500m }
};

var prices = products.Select(product => product.Price);

foreach (var price in prices)
{
Console.WriteLine(price);
}

実行結果です。

C#
120
300
2500

3-3. 抽出結果をToList()でListに変換する

Selectの結果をListとして使いたい場合は、ToList()を使います。

C#
List<string> names = users
.Select(user => user.Name)
.ToList();

ToList()を付けることで、IEnumerable<string>からList<string>に変換できます。

メソッドの戻り値としてListを返したい場合にもよく使います。

C#
public List<string> GetUserNames(List<User> users)
{
return users
.Select(user => user.Name)
.ToList();
}

3-4. Selectで型が変わる仕組みを理解する

Selectでは、元の型と結果の型が同じである必要はありません。

C#
var numbers = new List<int> { 1, 2, 3 };

var texts = numbers.Select(x => x.ToString());

この場合、元の要素はintですが、結果はstringになります。

C#
IEnumerable<string> texts = numbers.Select(x => x.ToString());

オブジェクトから文字列、オブジェクトから数値、オブジェクトから別のオブジェクトなど、自由に変換できるのがSelectの大きな特徴です。

4. SelectとWhereの違い

4-1. Selectは変換、Whereは絞り込み

SelectWhereはどちらもLINQでよく使いますが、役割が違います。

Selectは各要素を変換するために使います。

C#
var names = users.Select(user => user.Name);

Whereは条件に合う要素だけを絞り込むために使います。

C#
var adults = users.Where(user => user.Age >= 20);

簡単に言うと、Selectは「形を変える」、Whereは「数を減らす」メソッドです。

4-2. Whereだけを使うケース

条件に合う元のオブジェクトをそのまま取得したい場合は、Whereだけを使います。

C#
var adults = users.Where(user => user.Age >= 20);

foreach (var user in adults)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}

この場合、結果はUser型のままです。

C#
IEnumerable<User> adults = users.Where(user => user.Age >= 20);

「20歳以上のユーザーだけ欲しいが、Userオブジェクトの情報はそのまま使いたい」という場合はWhereが適しています。

4-3. Selectだけを使うケース

すべての要素を変換したいだけで、件数を絞り込まない場合はSelectだけを使います。

C#
var names = users.Select(user => user.Name);

この場合、すべてのユーザーから名前を取り出します。

C#
IEnumerable<string> names = users.Select(user => user.Name);

「全件を対象に、必要な値だけ取り出したい」という場面ではSelectを使います。

4-4. WhereとSelectを組み合わせる基本パターン

実務では、Whereで絞り込んでからSelectで必要な値に変換するパターンがよく使われます。

C#
var adultNames = users
.Where(user => user.Age >= 20)
.Select(user => user.Name)
.ToList();

このコードは、20歳以上のユーザーだけを対象にして、名前だけをListに変換しています。

処理の流れは次の通りです。

まずWhereで条件に合うユーザーを残し、その後SelectNameだけを取り出します。

4-5. WhereとSelectの順番で結果が変わるケース

WhereSelectの順番は重要です。

次のコードは正しく動きます。

C#
var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);

しかし、先にNameだけを取り出すと、その後でAgeを使えません。

C#
var names = users
.Select(user => user.Name)
.Where(name => name.Length >= 5);

この場合、Whereで扱っているのはUserではなくstringです。そのため、Ageにはアクセスできません。

C#
// エラーになる例
var names = users
.Select(user => user.Name)
.Where(user => user.Age >= 20);

Selectした後は型が変わることがあるため、その後の処理で使えるプロパティも変わります。

4-6. 初心者が間違えやすいSelectとWhereの使い分け

初心者がよく間違えるのは、条件で絞り込みたいのにSelectを使ってしまうケースです。

C#
// 条件判定の結果である bool の一覧になる
var results = users.Select(user => user.Age >= 20);

このコードは「20歳以上のユーザー一覧」ではなく、trueまたはfalseの一覧を作ります。

20歳以上のユーザーだけを取り出したいなら、Whereを使います。

C#
var adults = users.Where(user => user.Age >= 20);

名前だけを取り出したいなら、Selectを使います。

C#
var names = users.Select(user => user.Name);

条件に合う人の名前だけを取り出したいなら、WhereSelectを組み合わせます。

C#
var adultNames = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);

5. Selectで複数項目を抽出する方法

5-1. 匿名型で複数プロパティを抽出する

Selectでは、1つの値だけでなく複数の項目をまとめて抽出できます。よく使うのが匿名型です。

C#
var userSummaries = users.Select(user => new
{
user.Id,
user.Name
});

foreach (var user in userSummaries)
{
Console.WriteLine($"{user.Id}: {user.Name}");
}

new { user.Id, user.Name }のように書くと、IdNameを持つ一時的な型が作られます。

別名を付けることもできます。

C#
var userSummaries = users.Select(user => new
{
UserId = user.Id,
DisplayName = user.Name
});

5-2. DTOクラスに変換して抽出する

メソッドの戻り値として使う場合や、APIのレスポンスとして返す場合は、匿名型よりDTOクラスを使う方が適しています。

C#
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
C#
var userDtos = users.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
}).ToList();

DTOに変換すると、型名が明確になり、メソッドの戻り値にも指定できます。

C#
public List<UserDto> GetUserDtos(List<User> users)
{
return users.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
}).ToList();
}

5-3. タプルで複数項目を返す

簡単な処理であれば、タプルを使って複数項目を返すこともできます。

C#
var userTuples = users.Select(user => (user.Id, user.Name));

foreach (var user in userTuples)
{
Console.WriteLine($"{user.Id}: {user.Name}");
}

名前付きタプルにすると、より読みやすくなります。

C#
var userTuples = users.Select(user => (
UserId: user.Id,
UserName: user.Name
));
C#
foreach (var user in userTuples)
{
Console.WriteLine($"{user.UserId}: {user.UserName}");
}

5-4. new { x.Id, x.Name } のような書き方の意味

new { x.Id, x.Name }は匿名型を作る書き方です。

C#
var result = users.Select(x => new { x.Id, x.Name });

これは次のようなイメージです。

C#
var result = users.Select(x => new
{
Id = x.Id,
Name = x.Name
});

プロパティ名を省略した場合、元のプロパティ名がそのまま使われます。

別の名前にしたい場合は、明示的に指定します。

C#
var result = users.Select(x => new
{
UserId = x.Id,
UserName = x.Name
});

5-5. 匿名型・DTO・タプルの使い分け

匿名型は、メソッド内だけで一時的に使うデータに向いています。

C#
var result = users.Select(x => new { x.Id, x.Name });

DTOは、メソッドの戻り値、APIレスポンス、画面表示用データなど、型として明確に扱いたい場合に向いています。

C#
var result = users.Select(x => new UserDto
{
Id = x.Id,
Name = x.Name
});

タプルは、簡単な複数値を一時的に返したい場合に便利です。

C#
var result = users.Select(x => (x.Id, x.Name));

迷った場合は、短い処理なら匿名型、外部に返すデータならDTO、簡単な一時処理ならタプルと考えるとよいでしょう。

6. Selectの実践サンプルコード

6-1. 条件に合うデータだけを加工して取得する

WhereSelectを組み合わせると、条件に合うデータだけを加工して取得できます。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Tanaka", Age = 18 },
new User { Id = 2, Name = "Suzuki", Age = 25 },
new User { Id = 3, Name = "Sato", Age = 30 }
};

var adultDisplayNames = users
.Where(user => user.Age >= 20)
.Select(user => $"{user.Name}さん")
.ToList();

foreach (var name in adultDisplayNames)
{
Console.WriteLine(name);
}

実行結果です。

C#
Suzukiさん
Satoさん

6-2. IDと名前だけを抽出して一覧表示する

一覧画面では、すべての情報ではなくIDと名前だけ表示したいことがあります。

C#
var userList = users
.Select(user => new
{
user.Id,
user.Name
})
.ToList();

foreach (var user in userList)
{
Console.WriteLine($"{user.Id}: {user.Name}");
}

必要な項目だけに絞ることで、コードの意図がわかりやすくなります。

6-3. 金額を税込価格に変換する

商品価格を税込価格に変換する例です。

C#
var products = new List<Product>
{
new Product { Id = 1, Name = "Pen", Price = 100m },
new Product { Id = 2, Name = "Book", Price = 1000m },
new Product { Id = 3, Name = "Bag", Price = 5000m }
};

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

foreach (var product in displayProducts)
{
Console.WriteLine($"{product.Name}: {product.TaxIncludedPrice}円");
}

小数点を丸めたい場合は、Math.Roundを使えます。

C#
var displayProducts = products
.Select(product => new
{
product.Name,
TaxIncludedPrice = Math.Round(product.Price * 1.1m)
})
.ToList();

6-4. 日付や文字列を整形して表示用データを作る

Selectは画面表示用のデータ作成にも便利です。

C#
public class Order
{
public int Id { get; set; }
public DateTime OrderedAt { get; set; }
public decimal TotalAmount { get; set; }
}
C#
var orders = new List<Order>
{
new Order { Id = 1, OrderedAt = new DateTime(2026, 1, 10), TotalAmount = 2500m },
new Order { Id = 2, OrderedAt = new DateTime(2026, 1, 15), TotalAmount = 4800m }
};

var displayOrders = orders
.Select(order => new
{
order.Id,
OrderedDate = order.OrderedAt.ToString("yyyy/MM/dd"),
AmountText = $"{order.TotalAmount:N0}円"
})
.ToList();

foreach (var order in displayOrders)
{
Console.WriteLine($"{order.Id}: {order.OrderedDate} {order.AmountText}");
}

実行結果です。

C#
1: 2026/01/10 2,500
2: 2026/01/15 4,800

6-5. Entity Frameworkで必要な列だけをSelectする

Entity FrameworkでもSelectはよく使います。必要な列だけを取得することで、取得するデータ量を減らせます。

C#
var users = dbContext.Users
.Where(user => user.IsActive)
.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
})
.ToList();

このように書くと、アクティブなユーザーのうち、IdNameだけをDTOに変換して取得できます。

大量のデータを扱う場合、エンティティ全体を取得してから加工するより、最初から必要な項目だけをSelectする方が効率的です。

7. メソッド構文とクエリ構文のSelect

7-1. メソッド構文で書くSelect

これまで紹介してきた書き方はメソッド構文です。

C#
var names = users.Select(user => user.Name);

Whereと組み合わせる場合は次のように書きます。

C#
var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);

メソッドチェーンで処理をつなげられるため、C#ではよく使われる書き方です。

7-2. クエリ構文のselect句で書く方法

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

C#
var names =
from user in users
select user.Name;

Whereを組み合わせる場合は次のように書きます。

C#
var names =
from user in users
where user.Age >= 20
select user.Name;

SQLに慣れている人には読みやすい場合があります。

7-3. メソッド構文とクエリ構文の対応関係

次のメソッド構文とクエリ構文は、ほぼ同じ意味です。

C#
var names = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);
C#
var names =
from user in users
where user.Age >= 20
select user.Name;

どちらも、20歳以上のユーザーから名前だけを取り出しています。

C#のクエリ構文は、内部的にはLINQメソッドに変換されます。そのため、select句を理解していても、メソッド構文のSelectを理解しておくことは重要です。

7-4. 初心者にはどちらの書き方がおすすめか

初心者には、まずメソッド構文のSelectから覚えるのがおすすめです。

理由は、SelectWhereOrderByGroupByなどを同じ形でつなげて書けるからです。

C#
var result = users
.Where(user => user.Age >= 20)
.OrderBy(user => user.Name)
.Select(user => user.Name)
.ToList();

クエリ構文も便利ですが、実務ではメソッド構文が多く使われる場面も多いため、まずはコレクション.Select(x => ...)の形に慣れるとよいでしょう。

8. SelectManyとの違い

8-1. Selectは1要素を1つの結果に変換する

Selectは、基本的に1つの要素を1つの結果に変換します。

C#
var numbers = new List<int> { 1, 2, 3 };

var result = numbers.Select(x => x * 2);

この場合、3つの要素から3つの結果が作られます。

C#
1 -> 2
2 -> 4
3 -> 6

8-2. SelectManyは入れ子のコレクションを平坦化する

SelectManyは、入れ子になったコレクションを1つの平らなコレクションにするために使います。

たとえば、次のようなリストがあります。

C#
var groups = new List<List<string>>
{
new List<string> { "A", "B" },
new List<string> { "C", "D" }
};

Selectを使うと、結果はリストの中にリストがある形のままです。

C#
var selected = groups.Select(group => group);

一方、SelectManyを使うと、すべての文字列を1つの一覧にできます。

C#
var flattened = groups.SelectMany(group => group);

foreach (var item in flattened)
{
Console.WriteLine(item);
}

実行結果です。

C#
A
B
C
D

8-3. List<List<T>>や子要素の一覧取得でSelectManyを使う

親子関係のあるデータでもSelectManyは便利です。

C#
public class Department
{
public string Name { get; set; } = "";
public List<User> Users { get; set; } = new();
}

部署ごとにユーザー一覧がある場合、すべてのユーザーを1つの一覧として取り出せます。

C#
var allUsers = departments.SelectMany(department => department.Users);

Selectを使うと、部署ごとのユーザー一覧がそのまま返ります。

C#
var userGroups = departments.Select(department => department.Users);

結果のイメージは次の通りです。

C#
Select     -> List<List<User>> のような形
SelectMany -> List<User> のような平坦な形

8-4. SelectとSelectManyの使い分けサンプル

ユーザーごとの注文一覧を考えます。

C#
public class UserWithOrders
{
public string Name { get; set; } = "";
public List<Order> Orders { get; set; } = new();
}

ユーザーごとの注文リストをそのまま取得したい場合はSelectです。

C#
var orderGroups = users.Select(user => user.Orders);

すべての注文を1つの一覧にしたい場合はSelectManyです。

C#
var allOrders = users.SelectMany(user => user.Orders);

Selectは「各要素を変換する」、SelectManyは「変換した結果をさらに平坦化する」と覚えると理解しやすいです。

9. Selectを使うときの注意点

9-1. Selectだけでは処理が実行されない遅延実行

LINQのSelectは遅延実行です。つまり、Selectを書いただけでは処理はすぐに実行されません。

C#
var numbers = new List<int> { 1, 2, 3 };

var result = numbers.Select(x =>
{
Console.WriteLine($"変換: {x}");
return x * 2;
});

この時点では、Console.WriteLineは実行されません。

9-2. ToList()やforeachで実行されるタイミング

Selectの処理は、foreachで列挙したときやToList()を呼んだときに実行されます。

C#
var result = numbers.Select(x =>
{
Console.WriteLine($"変換: {x}");
return x * 2;
});

var list = result.ToList();

このToList()のタイミングで、各要素の変換処理が実行されます。

foreachでも同じです。

C#
foreach (var item in result)
{
Console.WriteLine(item);
}

遅延実行を理解していないと、「Selectを書いたのに処理されない」と感じることがあります。

9-3. nullが含まれる場合のエラー対策

コレクション内にnullが含まれる場合、プロパティにアクセスするとNullReferenceExceptionが発生することがあります。

C#
var users = new List<User?>
{
new User { Id = 1, Name = "Tanaka" },
null,
new User { Id = 2, Name = "Suzuki" }
};

// nullがあると危険
var names = users.Select(user => user.Name);

安全に書くには、Whereでnullを除外します。

C#
var names = users
.Where(user => user != null)
.Select(user => user!.Name)
.ToList();

または、null条件演算子を使います。

C#
var names = users
.Select(user => user?.Name ?? "名前なし")
.ToList();

9-4. 副作用のある処理をSelectに書かない

Selectは値を変換するためのメソッドです。ログ出力、データ更新、外部API呼び出しなどの副作用がある処理をSelectの中に書くのは避けましょう。

C#
// 推奨しにくい例
var result = users.Select(user =>
{
Console.WriteLine(user.Name);
user.Name = user.Name.ToUpper();
return user;
});

副作用のある処理はforeachで明示的に書く方が読みやすいです。

C#
foreach (var user in users)
{
Console.WriteLine(user.Name);
}

Selectは「変換結果を作るために使う」と意識すると、コードの可読性が上がります。

9-5. 可読性が下がる複雑なSelectの分け方

Selectの中に複雑な処理を書きすぎると、読みにくくなります。

C#
var result = users.Select(user => new
{
user.Id,
Text = $"{user.Name}({(user.Age >= 20 ? "成人" : "未成年")})"
});

短い処理なら問題ありませんが、条件分岐や計算が増える場合は、メソッドに分けると読みやすくなります。

C#
var result = users.Select(user => new
{
user.Id,
Text = CreateDisplayText(user)
});

static string CreateDisplayText(User user)
{
var ageLabel = user.Age >= 20 ? "成人" : "未成年";
return $"{user.Name}({ageLabel})";
}

Selectは便利ですが、1行に詰め込みすぎないことも大切です。

10. C# LINQ Selectでよくあるエラーと解決方法

10-1. Selectが使えないときはSystem.Linqを確認する

Selectが使えない場合、まずusing System.Linq;があるか確認しましょう。

C#
using System.Linq;

エラー例です。

C#
'List<User>' does not contain a definition for 'Select'

このようなエラーが出る場合、LINQの拡張メソッドが読み込まれていない可能性があります。

10-2. 型が合わないエラーの原因

Selectは変換後の型によって戻り値の型が変わります。

C#
var numbers = new List<int> { 1, 2, 3 };

IEnumerable<string> result = numbers.Select(x => x.ToString());

これは正しいコードです。

しかし、次のように型が合わないとエラーになります。

C#
// エラー
IEnumerable<int> result = numbers.Select(x => x.ToString());

x.ToString()の結果はstringなので、IEnumerable<int>には代入できません。

修正するには、変数の型を変換後の型に合わせます。

C#
IEnumerable<string> result = numbers.Select(x => x.ToString());

または、varを使うと型推論されます。

C#
var result = numbers.Select(x => x.ToString());

10-3. 匿名型の結果をメソッド外で扱いにくい問題

匿名型は便利ですが、メソッドの戻り値の型として明示しにくいという特徴があります。

C#
var result = users.Select(user => new
{
user.Id,
user.Name
});

メソッドの外でも使うデータなら、DTOクラスを作るのがおすすめです。

C#
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
C#
public List<UserDto> GetUsers(List<User> users)
{
return users.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
}).ToList();
}

匿名型は一時的な処理、DTOは外部に渡す処理に向いています。

10-4. NullReferenceExceptionを防ぐ書き方

Select内でnullの可能性がある値にアクセスすると、NullReferenceExceptionが発生します。

C#
var names = users.Select(user => user.Name.ToUpper());

Nameがnullの可能性がある場合は危険です。

安全に書くには、null条件演算子やnull合体演算子を使います。

C#
var names = users
.Select(user => user.Name?.ToUpper() ?? "NO NAME")
.ToList();

オブジェクト自体がnullの可能性がある場合は、次のように書けます。

C#
var names = users
.Select(user => user?.Name ?? "名前なし")
.ToList();

nullの可能性があるデータを扱うときは、Selectの中で安全にアクセスできているか確認しましょう。

10-5. IEnumerable<T>とList<T>の違いで迷ったときの対処法

Selectの結果はIEnumerable<T>です。

C#
IEnumerable<string> names = users.Select(user => user.Name);

Listとして使いたい場合はToList()を付けます。

C#
List<string> names = users
.Select(user => user.Name)
.ToList();

IEnumerable<T>は列挙できるデータ、List<T>は要素数の取得、追加、インデックスアクセスなどがしやすい具体的なコレクションです。

繰り返し表示するだけならIEnumerable<T>で十分です。

C#
foreach (var name in names)
{
Console.WriteLine(name);
}

後から要素を追加したい場合や、names[0]のようにインデックスでアクセスしたい場合はList<T>に変換しましょう。

11. C# LINQ Selectのよくある質問

11-1. Selectとforeachはどちらを使うべき?

新しいコレクションや変換結果を作りたい場合はSelectを使います。

C#
var names = users.Select(user => user.Name).ToList();

一方、単に処理を実行したい場合はforeachを使います。

C#
foreach (var user in users)
{
Console.WriteLine(user.Name);
}

Selectは変換、foreachは処理の実行と考えると使い分けやすいです。

11-2. Selectで複数条件を指定できる?

条件で絞り込みたい場合は、SelectではなくWhereを使います。

C#
var result = users
.Where(user => user.Age >= 20 && user.Name.StartsWith("S"))
.Select(user => user.Name)
.ToList();

この例では、20歳以上かつ名前がSで始まるユーザーだけを対象にし、名前を取り出しています。

Selectの中で条件分岐をすることもできますが、絞り込みにはWhereを使うのが基本です。

11-3. Selectの中でif文のような条件分岐はできる?

できます。簡単な条件分岐なら三項演算子を使うことが多いです。

C#
var labels = users
.Select(user => user.Age >= 20 ? "成人" : "未成年")
.ToList();

複雑な条件分岐が必要な場合は、ブロック形式のラムダ式を使えます。

C#
var labels = users
.Select(user =>
{
if (user.Age >= 65)
{
return "シニア";
}

if (user.Age >= 20)
{
return "成人";
}

return "未成年";
})
.ToList();

ただし、複雑になりすぎる場合は別メソッドに分けると読みやすくなります。

11-4. Selectでインデックス番号を使うには?

Selectには、要素とインデックスを受け取れるオーバーロードがあります。

C#
var names = new List<string> { "Tanaka", "Suzuki", "Sato" };

var result = names.Select((name, index) => new
{
Index = index,
Name = name
});

foreach (var item in result)
{
Console.WriteLine($"{item.Index}: {item.Name}");
}

実行結果です。

C#
0: Tanaka
1: Suzuki
2: Sato

番号を1から始めたい場合は、index + 1にします。

C#
var result = names.Select((name, index) => new
{
No = index + 1,
Name = name
});

11-5. Selectはパフォーマンスに影響する?

Select自体はよく使われる標準的なLINQメソッドであり、通常の用途では大きな問題になることは少ないです。

ただし、大量データを扱う場合やEntity Frameworkでデータベースアクセスをする場合は、使い方に注意が必要です。

たとえば、必要な列だけをSelectで取得するのは効率的です。

C#
var users = dbContext.Users
.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
})
.ToList();

一方で、すべてのデータをToList()でメモリに読み込んでからSelectする場合、データ量によっては無駄が増えます。

C#
// データを全件読み込んでから変換するため、場合によっては非効率
var users = dbContext.Users
.ToList()
.Select(user => new UserDto
{
Id = user.Id,
Name = user.Name
});

データベースを使う場合は、できるだけToList()の前にWhereSelectを書き、必要なデータだけを取得するようにしましょう。

まとめ

C# LINQのSelectは、コレクションの各要素を別の形に変換するためのメソッドです。

数値を計算する、文字列を加工する、オブジェクトのプロパティを抽出する、匿名型やDTOに変換するなど、さまざまな場面で使えます。

SelectWhereの違いも重要です。Selectは変換、Whereは絞り込みです。条件に合うデータだけを取り出して加工したい場合は、Whereで絞り込み、Selectで変換するのが基本です。

C#
var result = users
.Where(user => user.Age >= 20)
.Select(user => user.Name)
.ToList();

複数項目を抽出したい場合は、匿名型、DTO、タプルを使います。

C#
var result = users.Select(user => new
{
user.Id,
user.Name
});

また、Selectは遅延実行されるため、ToList()foreachで列挙されるタイミングで実際の処理が行われます。null対策や型の違いにも注意しましょう。

C#でデータ加工を行ううえで、LINQのSelectは非常に基本的で重要な機能です。まずは「各要素を変換するメソッド」と理解し、WhereToList()と組み合わせながら使い方に慣れていきましょう。