りおんクロニクル


C# × 設計(SOLID / DI / レイヤード)|業務アプリを長期運用できる構造にする実務ガイド【2026年版】

Home【2026年版】C# / .NET入門と実践ガイド|基礎・業務アプリ開発・SQLite連携まで体系的に解説

C#で業務アプリを作るとき、 「とりあえず動くコード」 から一歩進んで、 「長期運用に耐える設計」 にしておくことが重要です。 この記事では、SOLID原則・DI・レイヤードアーキテクチャ を 現場目線でコンパクトに整理します。

この記事でわかること
・SOLID原則の“実務で効く”要点
・DI(依存性注入)の考え方と書き方
・レイヤードアーキテクチャの構造(UI / アプリ / ドメイン / インフラ)
・インターフェース設計のコツ
・テストしやすい構造の作り方
・WPF / Web API / コンソールでの適用イメージ

1. SOLID原則を“現場目線”でざっくり押さえる

■ 1-1. S:単一責任の原則(Single Responsibility)

「クラスは1つのことだけをする」 画面制御・DBアクセス・計算ロジックを1クラスに詰め込まない。

■ 1-2. O:開放/閉鎖の原則(Open/Closed)

「拡張に開き、修正に閉じる」 if文を増やすのではなく、クラスを追加して差し替える。

■ 1-3. D:依存性逆転の原則(Dependency Inversion)

「具象ではなく抽象(インターフェース)に依存する」 これが DI とレイヤードの土台になります。

全部を完璧に守る必要はなく、S と D を意識するだけでも設計はかなり良くなります。

2. DI(依存性注入)の基本と実務パターン

■ 2-1. 依存性注入とは

クラスの中で new しないで、 外から必要なオブジェクトを渡してもらう 設計です。

// 悪い例:中で new してしまう
public class OrderService
{
    private readonly OrderRepository _repo = new OrderRepository();
}

// 良い例:コンストラクタで受け取る
public class OrderService
{
    private readonly IOrderRepository _repo;
    public OrderService(IOrderRepository repo)
    {
        _repo = repo;
    }
}

■ 2-2. .NET のDIコンテナを使う(ASP.NET Core / WPFホスト)

builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<OrderService>();

これで OrderService を要求すると、自動的に IOrderRepository が注入 されます。

■ 2-3. テストしやすくなる

var mockRepo = new Mock<IOrderRepository>>();
var service = new OrderService(mockRepo.Object);

DBを触らずにユニットテストが書けるようになります。

3. レイヤードアーキテクチャの基本構造

■ 3-1. 典型的な4層構造

上の層は下の層に依存するが、逆は依存しない という矢印を意識します。

■ 3-2. 依存関係のイメージ

UI → アプリケーション → ドメイン
                     ↘ インフラ

ドメインはインフラを知らず、インフラがドメインを知る構造にします。

4. インターフェースで“境界”を作る

■ 4-1. リポジトリインターフェース

public interface IOrderRepository
{
    Task<Order?> FindAsync(int id);
    Task SaveAsync(Order order);
}

■ 4-2. 実装はインフラ層に置く

public class SqlOrderRepository : IOrderRepository
{
    private readonly DbConnection _con;
    public SqlOrderRepository(DbConnection con) { _con = con; }

    public Task<Order?> FindAsync(int id) { ... }
    public Task SaveAsync(Order order) { ... }
}

アプリケーション層・ドメイン層は IOrderRepository だけを知り、 SQL Server / SQLite / API などの具体実装は知らない という状態にします。

5. 実務でよくある構成例(Web API)

■ 5-1. Controller → Service → Repository

// プレゼンテーション層(Web API)
[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    private readonly OrderService _service;
    public OrdersController(OrderService service) { _service = service; }

    [HttpPost]
    public async Task<IActionResult> Create(CreateOrderRequest req)
    {
        await _service.CreateAsync(req);
        return Ok();
    }
}
// アプリケーション層
public class OrderService
{
    private readonly IOrderRepository _repo;
    public OrderService(IOrderRepository repo) { _repo = repo; }

    public async Task CreateAsync(CreateOrderRequest req)
    {
        var order = new Order(req.CustomerId, req.Items);
        await _repo.SaveAsync(order);
    }
}

Controller は「HTTPのことだけ」、Service は「ユースケースだけ」、Repository は「DBだけ」を担当します。

6. 実務でよくある構成例(WPF)

■ 6-1. View → ViewModel → Service → Repository

MVVM とレイヤードを組み合わせると、画面とロジックがきれいに分離できます。

7. 設計を“やりすぎない”ための現場ルール

■ 7-1. 小規模なら3層でも十分

最初から完璧なクリーンアーキテクチャを目指さなくてOK。

■ 7-2. 変更が多いところから分離する

ここをインターフェースで切っておくだけでも、後々の変更コストが大きく下がります。

8. 業務アプリ向けベストプラクティス

まとめ:C#設計は“分ける・依存を逆転させる・差し替え可能にする”が軸になる

「最初は小さく、でも後から壊さずに拡張したい」 という現場のニーズに対して、 SOLID × DI × レイヤードは非常に相性の良い組み合わせです。 この記事をベースに、あなたのプロジェクト規模に合った設計レベルを選んでみてください。

前のページ  次のページ