C#/.NET バックエンド開発者向け面接質問:完全ガイド

Milad Bonakdar
著者
ASP.NET Core、Entity Framework、Dependency Injection、システム設計を網羅した、C#と.NETバックエンド開発の面接対策に必須の質問集です。
はじめに
C# と .NET は著しく進化し、高性能なバックエンドシステムを構築するための強力なクロスプラットフォームエコシステムになりました。.NET Core(そして現在の .NET 5+)の登場により、クラウドネイティブアプリケーション、マイクロサービス、エンタープライズソリューションにとって最良の選択肢となっています。
このガイドでは、C# と .NET を専門とするバックエンド開発者向けの重要な面接の質問を取り上げます。言語の基礎、ASP.NET Core アーキテクチャ、Entity Framework を使用したデータベースインタラクション、および次の面接の準備に役立つベストプラクティスについて説明します。
C# の言語の基礎
1. C# における struct と class の違いは何ですか?
回答:
- Class: 参照型(ヒープに割り当てられます)。クラスオブジェクトをメソッドに渡すと、メモリロケーションへの参照を渡すことになります。メソッド内の変更は、元のオブジェクトに影響を与えます。継承をサポートします。
- Struct: 値型(スタックに割り当てられます)。構造体を渡すと、データのコピーが渡されます。メソッド内の変更は、元の構造体に影響を与えません。継承はサポートしていません(ただし、インターフェースを実装できます)。
- 使用法:
structは、単一の値を表す小さく、不変のデータ構造(Point、Colorなど)に使用します。他のほとんどのオブジェクトにはclassを使用します。
希少度: 一般的 難易度: 簡単
2. async と await について説明してください。これはどのようにスケーラビリティに役立ちますか?
回答:
async と await は、非同期プログラミングに使用されるキーワードです。
- メカニズム:
awaitキーワードが検出されると、メソッドの実行が一時停止され、スレッドは他のリクエストを処理するためにスレッドプールに戻されます。待機されたタスクが完了すると、実行が再開されます(場合によっては別のスレッドで)。 - スケーラビリティ: Web サーバー(Kestrel など)では、スレッドは限られたリソースです。スレッドが I/O(データベース、ネットワーク)を待機してブロックされると、他のリクエストを処理できません。Async を使用すると、I/O 操作中にスレッドをブロックしないことで、サーバーはより少ないスレッドでより多くの同時リクエストを処理できます。
希少度: 非常に一般的 難易度: 普通
3. 依存性注入(DI)とは何ですか?また、.NET でどのように実装されますか?
回答: 依存性注入は、クラスの依存関係が内部で作成されるのではなく、外部から提供される設計パターンです。
- .NET での実装: ASP.NET Core には、組み込みの DI コンテナがあります。
Program.cs(または古いバージョンのStartup.cs)でサービスを登録し、コンストラクタインジェクションを介してそれらを注入します。 - ライフタイム:
- Transient: リクエストされるたびに作成されます。
- Scoped: クライアントリクエスト(HTTP リクエスト)ごとに 1 回作成されます。
- Singleton: 最初にリクエストされたときに作成され、後続のすべてのリクエストで共有されます。
希少度: 非常に一般的 難易度: 普通
4. IEnumerable<T> と IQueryable<T> の違いは何ですか?
回答:
IEnumerable<T>: クエリをメモリ内で実行します。データベース(EF Core)で使用する場合、サーバーからクライアントメモリにすべてのデータをフェッチし、その後 フィルタリングします。LINQ to Objects に適しています。IQueryable<T>: クエリをリモートで実行します(例:SQL サーバー上)。SQL クエリに変換される式ツリーを構築します。フィルタリングはデータベース側で行われるため、大規模なデータセットでははるかに効率的です。
希少度: 一般的 難易度: 普通
5. 拡張メソッドとは何ですか?
回答: 拡張メソッドを使用すると、新しい派生型を作成したり、再コンパイルしたり、元の型を変更したりせずに、既存の型にメソッドを「追加」できます。
- 構文: 静的クラスの静的メソッドとして定義されます。最初のパラメータは、メソッドが動作する型を指定し、その前に
thisキーワードを付けます。 - 例:
stringクラスにWordCount()メソッドを追加します。
希少度: 一般的 難易度: 簡単
ASP.NET Core とアーキテクチャ
6. ASP.NET Core におけるミドルウェアとは何ですか?
回答: ミドルウェアは、リクエストとレスポンスを処理するためにアプリケーションパイプラインに組み立てられるソフトウェアコンポーネントです。
- パイプライン: 各コンポーネントは、リクエストをパイプライン内の次のコンポーネントに渡すかどうかを選択し、次のコンポーネントが呼び出される前後に作業を実行できます。
- 例: 認証、認可、ロギング、例外処理、静的ファイル配信。
- 順序が重要:
Program.csにミドルウェアが追加される順序によって、実行順序が決まります。
希少度: 非常に一般的 難易度: 普通
7. .NET Core と .NET Framework の違いについて説明してください。
回答:
- .NET Framework: 元の Windows 専用の実装。成熟していますが、Windows に縛られています。
- .NET Core(現在は単に .NET): クロスプラットフォーム、オープンソース、およびモジュール式の実装。Windows、Linux、および macOS で実行されます。高いパフォーマンスとクラウドデプロイメントに最適化されています。
- 主な違い: クロスプラットフォームのサポート、マイクロサービスアーキテクチャに適している、より高いパフォーマンス、サイドバイサイドのバージョン管理。
希少度: 一般的 難易度: 簡単
8. Kestrel とは何ですか?
回答: Kestrel は、ASP.NET Core テンプレートにデフォルトで含まれているクロスプラットフォーム、オープンソース、イベント駆動型の Web サーバーです。
- 役割: HTTP リクエストをリッスンし、それらをアプリケーションに渡します。
- 使用法: スタンドアロン(エッジサーバー)または IIS、Nginx、Apache などのリバースプロキシの背後で実行できます。セキュリティ、ロードバランシング、および SSL 終端を処理するために、本番環境ではリバースプロキシを使用することをお勧めします。
希少度: 普通 難易度: 普通
9. ASP.NET Core でグローバル例外処理をどのように処理しますか?
回答: すべてのコントローラーで try-catch ブロックを使用する代わりに、グローバル例外処理にはミドルウェアを使用する必要があります。
UseExceptionHandler: 例外をキャッチし、ログに記録し、代替パイプライン(通常はエラーページまたは API レスポンスを指す)でリクエストを再実行する組み込みのミドルウェア。- カスタムミドルウェア: カスタムミドルウェアを作成して例外をキャッチし、標準化された JSON エラーレスポンス(例:
ProblemDetails)を返すことができます。
希少度: 一般的 難易度: 普通
データベースと Entity Framework
10. Entity Framework Core(EF Core)とは何ですか?Code-First と Database-First の違いは?
回答: EF Core は、.NET 用のオブジェクトリレーショナルマッパー(ORM)です。開発者は .NET オブジェクトを使用してデータベースを操作できます。
- Code-First: 最初にドメインクラス(エンティティ)を定義し、EF Core は移行を使用してそれらに基づいてデータベーススキーマを作成/更新します。新しいプロジェクトに推奨されます。
- Database-First: 既存のデータベースがあり、EF Core はスキーマに基づいて .NET クラス(スキャフォールディング)を生成します。
希少度: 一般的 難易度: 簡単
11. EF Core の N+1 問題とは何ですか?また、どのように修正しますか?
回答: N+1 問題は、エンティティのリスト(1 つのクエリ)をフェッチし、ループ内の各アイテムに関連エンティティにアクセスすると、N 個の追加クエリが発生する場合に発生します。
- 修正:
.Include()メソッドを使用して事前読み込みを使用します。これにより、SQLJOINが生成され、関連データが 1 つのクエリでフェッチされます。 - 例:
context.Orders.Include(o => o.Customer).ToList();
希少度: 非常に一般的 難易度: 普通
12. リポジトリパターンについて説明してください。EF Core で使用する理由は何ですか?
回答: リポジトリパターンは、ドメインオブジェクトへのアクセスにコレクションのようなインターフェースを使用して、ドメイン層とデータマッピング層を仲介します。
- 長所: アプリケーションを特定のデータアクセス技術(EF Core)から分離し、単体テストを容易にし(リポジトリをモックできます)、データアクセスロジックを一元化します。
- 短所/議論: EF Core の
DbContextは、すでにリポジトリ/Unit of Work パターンの実装です。別のレイヤーを追加すると、冗長になる場合があります(「抽象化の上の抽象化」)。
希少度: 一般的 難易度: 難しい
REST API と Web サービス
13. HTTP 動詞とその典型的な使用法は何ですか?
回答:
- GET: リソースを取得します。安全でべき等です。
- POST: 新しいリソースを作成します。べき等ではありません。
- PUT: 既存のリソースを更新/置換します。べき等です。
- PATCH: リソースを部分的に更新します。必ずしもべき等ではありません(通常はそうですが)。
- DELETE: リソースを削除します。べき等です。
希少度: 一般的 難易度: 簡単
14. 401 Unauthorized と 403 Forbidden の違いは何ですか?
回答:
- 401 Unauthorized: ユーザーが認証されていません。クライアントはログインして再試行する必要があります。「あなたは誰だかわかりません。」
- 403 Forbidden: ユーザーは認証されていますが、リソースにアクセスする権限がありません。「私はあなたが誰であるかを知っていますが、これはできません。」
希少度: 一般的 難易度: 簡単
テストとベストプラクティス
15. 単体テストと統合テストの違いは何ですか?
回答:
- 単体テスト: コードの小さな単位(通常はメソッド)を分離してテストします。依存関係は(Moq などのツールを使用して)モックされます。高速で信頼性があります。
- 統合テスト: アプリケーションのさまざまな部分がどのように連携するかをテストします(例:API エンドポイント + データベース)。遅いですが、実際のシステム動作を検証します。
希少度: 一般的 難易度: 簡単
16. 単体テストで依存関係をどのようにモックしますか?
回答: Moq や NSubstitute などのモックフレームワークを使用して、インターフェースの偽の実装を作成します。
- 目的: テスト対象のクラスを分離すること。たとえば、
UserServiceをテストする場合、実際のデータベースにアクセスしないようにIUserRepositoryをモックします。 - 例(Moq):
希少度: 一般的 難易度: 普通
17. SOLID 原則とは何ですか?1 つの例を挙げてください。
回答: SOLID は、ソフトウェアをより理解しやすく、柔軟で、保守しやすくするための 5 つの設計原則の頭字語です。
- S 単一責任原則(SRP)
- O オープン/クローズド原則(OCP)
- L リスコフの置換原則(LSP)
- I インターフェース分離原則(ISP)
- D 依存性逆転原則(DIP)
- 例(DIP): 高レベルモジュールは低レベルモジュールに依存すべきではありません。両方とも抽象化に依存する必要があります。これは、依存性注入の基礎です。
希少度: 一般的 難易度: 難しい
18. ボクシングとアンボクシングとは何ですか?それを避ける理由は何ですか?
回答:
- ボクシング: 値型(
intなど)を参照型(object)に変換します。ヒープにメモリを割り当てます。 - アンボクシング: 参照型を値型に戻します。
- パフォーマンス: どちらも高価な操作です(メモリ割り当て、型チェック)。ジェネリック(
List<T>)は、古いコレクション(ArrayList)と比較して、ボクシング/アンボクシングを回避するのに役立ちます。
希少度: 一般的 難易度: 普通
19. C# の using ステートメントとは何ですか?
回答:
using ステートメントは、IDisposable オブジェクトの正しい使用を保証する便利な構文を提供します。
- メカニズム: ブロックが終了すると(例外が発生した場合でも)、オブジェクトの
Dispose()メソッドを自動的に呼び出します。 - 最新の構文:
using var file = File.OpenRead("path");(中かっこは不要で、スコープの最後に破棄されます)。
希少度: 一般的 難易度: 簡単
20. 「責任の連鎖」パターンのコンテキストでミドルウェアの概念を説明してください。
回答: ASP.NET Core ミドルウェアは、責任の連鎖パターンの古典的な実装です。
- パターン: リクエストはハンドラーのチェーンに沿って渡されます。各ハンドラーは、リクエストを処理するか、チェーン内の次のハンドラーに渡すかを決定します。
- アプリケーション: .NET では、
RequestDelegateが次のハンドラーを表します。ミドルウェアコンポーネントは、リクエストパイプラインを形成するためにチェーンされます。
希少度: まれ 難易度: 難しい



