C#/.NETバックエンド面接質問と回答

Milad Bonakdar
著者
ASP.NET Core、EF Core、async、DI、REST API、テスト、アーキテクチャを中心に、C#/.NETバックエンド面接を実践的に対策できます。
はじめに
C#/.NETバックエンド開発者の面接では、ASP.NET CoreでAPIを作る方法、EF Coreでデータアクセスを効率化する考え方、スレッドをブロックしないasyncコード、Dependency Injectionによるサービス設計を説明できることが重要です。強い回答は、概念をパフォーマンス、信頼性、テストしやすさ、保守性といった実務上の判断につなげます。
このガイドは実践的なチェックリストとして使ってください。短い回答を確認したうえで、各回答を自分のプロジェクト、インターン、技術課題、解決した不具合の具体例に結びつけて練習しましょう。
C# の言語の基礎
1. C# における struct と class の違いは何ですか?
回答:
- Class: 参照型(ヒープに割り当てられます)。クラスオブジェクトをメソッドに渡すと、メモリロケーションへの参照を渡すことになります。メソッド内の変更は、元のオブジェクトに影響を与えます。継承をサポートします。
- Struct: 値型(スタックに割り当てられます)。構造体を渡すと、データのコピーが渡されます。メソッド内の変更は、元の構造体に影響を与えません。継承はサポートしていません(ただし、インターフェースを実装できます)。
- 使用法:
structは、単一の値を表す小さく、不変のデータ構造(Point、Colorなど)に使用します。他のほとんどのオブジェクトにはclassを使用します。
希少度: 一般的 難易度: 簡単
2. async と await について説明してください。これはどのようにスケーラビリティに役立ちますか?
回答:
async と await は、I/O処理の待機中にメソッドを一時停止し、Task の完了後に処理を再開するための仕組みです。
- メカニズム:
awaitは新しいスレッドを作りません。データベース、ファイル、ネットワーク呼び出しではリクエストスレッドを解放します。 - スケーラビリティ: I/O中心のASP.NET Coreエンドポイントではスループット向上に役立ちますが、CPU負荷の高い処理を速くするものではありません。
- 面接のコツ: データベースI/Oでは
CancellationToken、ToListAsync、SaveChangesAsyncなどに触れると実務的です。
希少度: 非常に一般的 難易度: 普通
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: クロスプラットフォームでオープンソースの後継ラインです。.NET 5以降は通常
.NETと呼ばれ、現在のリリースにはC# 14をサポートする.NET 10 LTSが含まれます。 - 主な違い: モダン.NETはLinuxコンテナ、サイドバイサイド実行、最新のASP.NET Core機能、継続的なランタイム改善を使えるため、新しいバックエンドAPIの標準的な選択肢です。
希少度: 一般的 難易度: 簡単
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問題は、エンティティ一覧を取得したあと、ループ内で各要素の関連データを読み込むことで多数の追加クエリが発生する問題です。
- 修正:
Include、フィルター付きInclude、プロジェクション、明示的読み込みで関連データを意図的に読み込みます。重要な処理ではlazy loadingを避けます。 - 例:
await context.Orders.Include(o => o.Customer).ToListAsync(); - トレードオフ: 複数のコレクションを含める場合は、split queryやプロジェクションでcartesian explosionや不要な列の読み込みを避けます。
希少度: 非常に一般的 難易度: 普通
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が次のハンドラーを表します。ミドルウェアコンポーネントは、リクエストパイプラインを形成するためにチェーンされます。
希少度: まれ 難易度: 難しい


