【C#】global using完全ガイド|暗黙的using・.csproj制御・C# 12 any type alias・名前衝突・実践テンプレートまで

【C#】global using の使い方とメリット C#

C# 10 で導入された global using は、プロジェクト全体で有効な using を1箇所にまとめる仕組みです。さらに .NET 6+ の暗黙的 using(Implicit Usings)により、SystemSystem.LinqSystem.Threading.Tasks 等が自動で global using として追加されるため、新しいプロジェクトでは using をほとんど書かずにコーディングできます。

本記事では global using の3つの形式・暗黙的 using の SDK 別デフォルト・.csproj での追加/削除制御・C# 12 の any type aliasglobal using static と拡張メソッドの制限・名前衝突の解決策・テストプロジェクト用テンプレート・ NuGet ライブラリでの注意点まで体系的に解説します。

スポンサーリンク

global using の3つの形式

形式 構文 効果
名前空間 using global using System.Linq; プロジェクト全ファイルで名前空間がインポートされる
using static global using static System.Math; 静的メンバーを型名なしで呼べる
エイリアス global using Json = System.Text.Json.JsonSerializer; 短縮名をプロジェクト全体で使える
GlobalUsings.cs — 3つの形式の実例
// ① 名前空間 using: 最も一般的
global using System.Collections.Generic;
global using System.Text;
global using Microsoft.Extensions.Logging;

// ② using static: 頻繁に使う静的メソッドをグローバル化
global using static System.Console;  // Write / WriteLine を直接呼べる
global using static System.Math;     // Sqrt / Abs を直接呼べる

// ③ エイリアス: 長い型名を短くする
global using JsonOptions = System.Text.Json.JsonSerializerOptions;
global using IDb = Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade;

// どの .cs ファイルからも有効
// 例: Program.cs
var opt = new JsonOptions { WriteIndented = true };
WriteLine(Sqrt(16));  // Console.WriteLine, Math.Sqrt が型名なしで呼べる
GlobalUsings.cs は慣習名
global using はプロジェクト内のどの .cs ファイルに書いても有効ですが、慣習的に GlobalUsings.cs という専用ファイルにまとめます。複数ファイルに分散するとどこにどの global using があるか分からなくなるため、1ファイルに集約してください。ファイルはプロジェクトルート直下に置くのが一般的です。

暗黙的 using(Implicit Usings)— .NET 6+ のデフォルト

.NET 6 以降のプロジェクトテンプレートでは .csproj<ImplicitUsings>enable</ImplicitUsings> が設定されており、SDK の種類に応じて自動で global using が追加されます。多くの基本名前空間を書く必要がなくなりますが、「見えない using が何をインポートしているか」を知っておく必要があります。

SDK 自動インポートされる名前空間
Microsoft.NET.Sdk(Console/Library) System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading, System.Threading.Tasks
Microsoft.NET.Sdk.Web(ASP.NET Core) 上記 + System.Net.Http.Json, Microsoft.AspNetCore.Builder, Microsoft.AspNetCore.Hosting, Microsoft.AspNetCore.Http, Microsoft.AspNetCore.Routing, Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.Hosting, Microsoft.Extensions.Logging
Microsoft.NET.Sdk.Worker Console SDK + Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.Hosting, Microsoft.Extensions.Logging
自動生成ファイルの確認方法
// 暗黙的 using は obj フォルダに自動生成される
// obj/Debug/net8.0/ProjectName.GlobalUsings.g.cs の中身:

// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;

// 「なぜ書いていない using が通るのか」分からないときはこのファイルを確認する
// global:: プレフィックスはルート名前空間を明示する記法

.csproj での global using 制御

.csproj — 暗黙的 using の有効化/無効化と個別制御
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>

    <!-- 暗黙的 using を有効化(デフォルトで enable) -->
    <ImplicitUsings>enable</ImplicitUsings>

    <!-- 無効化したい場合 -->
    <!-- <ImplicitUsings>disable</ImplicitUsings> -->
  </PropertyGroup>

  <ItemGroup>
    <!-- 暗黙的 using に追加 -->
    <Using Include="Microsoft.Extensions.Options" />
    <Using Include="System.Text.Json" />

    <!-- 暗黙的 using から除外(名前衝突の解決に有用) -->
    <Using Remove="System.Net.Http" />

    <!-- static using を追加 -->
    <Using Include="System.Math" Static="True" />

    <!-- エイリアスを追加 -->
    <Using Include="System.Text.Json.JsonSerializer" Alias="Json" />
  </ItemGroup>
</Project>
.csproj と GlobalUsings.cs はどちらを使うべきか
両方を併用するのが一般的ですが、役割を分けるのがベストプラクティスです。.csproj の <Using> は「暗黙的 using の追加/削除」(SDK デフォルトの調整)に使い、GlobalUsings.cs は「プロジェクト固有の global using」をまとめる場所にします。.csproj に大量の <Using> を書くと XML が膨れて読みにくくなるため、5個を超えるなら GlobalUsings.cs にまとめた方がすっきりします。

C# 12 の any type alias — 型エイリアスの大幅拡張

C# 12 以前の using alias は名前空間かクラスにしか使えませんでしたが、C# 12(.NET 8+)からはあらゆる型にエイリアスを付けられるようになりました。タプル・配列・ジェネリック型・nullable 型も対象です。

C# 12 の using alias any type
// C# 12+: タプル型にエイリアス
global using Point = (int X, int Y);
global using Rgb   = (byte R, byte G, byte B);

Point origin = (0, 0);
Console.WriteLine(origin.X);

// ジェネリック型にエイリアス
global using UserDict = System.Collections.Generic.Dictionary<string, User>;
global using StringList = System.Collections.Generic.List<string>;

UserDict cache = new();

// nullable 型にエイリアス
global using MaybeInt = int?;

// 配列型にエイリアス
global using Matrix = double[][];

// C# 12 以前では不可能だった例:
// using Point = (int, int);            // NG in C# 11
// using Dict  = Dictionary<string, int>; // NG in C# 11(ジェネリック open 不可)

global using static と拡張メソッド

static using では拡張メソッドもスコープに入る
// using static で静的クラスを指定すると
// その型の静的メンバーに加えて「拡張メソッド」もインポートされる

global using static System.Linq.Enumerable;
// → Where, Select, ToList 等の拡張メソッドがプロジェクト全体で使える
// ただし System.Linq は暗黙的 using で既にインポート済みなので通常不要

// 実用例: 自作のヘルパー拡張メソッドをグローバル化
public static class StringExtensions
{
    public static string Truncate(this string s, int maxLen)
        => s.Length <= maxLen ? s : s[..maxLen] + "...";
}

// GlobalUsings.cs に追加
// global using static MyApp.Helpers.StringExtensions;

// → プロジェクト全体で "長い文字列".Truncate(10) が使える
// ただし拡張メソッドの大量グローバル化は名前衝突リスクを高めるため
// よく考えてから追加する
global using static の濫用は名前衝突の温床
global using static でインポートした静的メンバーは全ファイルでスコープに入るため、同名のメソッドが複数のクラスにあるとコンパイルエラー(曖昧な呼び出し)になります。Console.WriteLine のように極めて頻繁に使うもの以外は、グローバル化せずファイルごとの using static にとどめた方が安全です。

名前衝突の解決パターン

同名の型が複数 namespace に存在する場合
// global using System.Threading; と global using System.Timers; を両方入れると
// Timer が曖昧になる

// 解決① — global using alias で明示的に区別
global using SysTimer  = System.Timers.Timer;
global using ThrdTimer = System.Threading.Timer;

var t1 = new SysTimer(1000);
var t2 = new ThrdTimer(_ => { }, null, 0, 1000);

// 解決② — .csproj で一方を除外
// <Using Remove="System.Timers" />

// 解決③ — ファイル内のローカル using alias(global ではない)で上書き
using Timer = System.Timers.Timer;

// 解決④ — 完全修飾名で書く
var timer = new System.Threading.Timer(_ => { }, null, 0, 1000);
NuGet パッケージ間の名前衝突
// 2つの NuGet が同名の型を持つケース(例: JsonSerializer, ILogger)
// → 完全修飾名 or alias が最も確実

// extern alias: アセンブリレベルで名前空間を分離(稀なケース)
// .csproj で設定:
// <ProjectReference Include="..." Aliases="MyAlias" />
// ソースコードで:
// extern alias MyAlias;
// using MyAlias::SomeNamespace.SomeClass;

実践テンプレート集

Web API プロジェクト用 GlobalUsings.cs
// Web API では暗黙的 using で大半がカバーされるため追記は少ない
global using System.ComponentModel.DataAnnotations;
global using Microsoft.EntityFrameworkCore;
global using MyApp.Models;
global using MyApp.Services;
Console / Worker Service プロジェクト用
global using Microsoft.Extensions.Options;
global using System.Text.Json;
global using MyApp.Core;
global using MyApp.Infrastructure;
テストプロジェクト用 GlobalUsings.cs
global using Xunit;
global using Moq;
global using FluentAssertions;
global using Microsoft.Extensions.Logging.Abstractions;
global using MyApp.Models;
global using MyApp.Services;
ライブラリプロジェクト用
// ライブラリの GlobalUsings.cs は最小限にする
// ライブラリ利用者の名前空間に影響を与えるリスクがある
global using System.Diagnostics;
global using System.Runtime.CompilerServices;
// ※ ライブラリ内部の global using は利用者プロジェクトに伝播しない(安全)

file スコープ名前空間(C# 10)との関係

global using と file-scoped namespace
// C# 10 で file-scoped namespace も導入された
// global using + file-scoped namespace を組み合わせるとファイルがシンプルに

// Before(C# 9 以前)
using System;
using System.Collections.Generic;
using System.Linq;

namespace MyApp.Models
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; } = "";
    }
}

// After(C# 10+: global using + file-scoped namespace)
// System, System.Collections.Generic, System.Linq は暗黙的 using で不要
namespace MyApp.Models;

public class User
{
    public int Id { get; set; }
    public string Name { get; init; } = "";
}

// using 宣言0行・namespace のインデント1段減 → ファイルが大幅にスッキリ
.editorconfig で全体に適用
csharp_style_namespace_declarations = file_scoped.editorconfig に設定すると、チーム全体で file-scoped namespace を強制できます。global using との相乗効果で、ファイルの冒頭が「namespace宣言1行 → 本題」となり、コードレビュー時のノイズが大幅に減ります。

パフォーマンスとコンパイルへの影響

global usingコンパイル時のみの機能であり、ランタイムの実行速度やメモリ使用量には一切影響しません。IL(中間言語)レベルでは通常の using と同じ完全修飾名に解決されます。

影響 詳細
ランタイム性能 影響なし(IL は同一)
コンパイル時間 ごく僅かに増加(名前解決スコープが広がるため)。実測で体感差はほぼない
IntelliSense グローバルにインポートされた型が補完候補に出る → 候補が増えすぎると感じる場合もある
アセンブリサイズ 影響なし

よくある落とし穴

落とし穴① — 暗黙的 using を知らずに名前衝突
// 暗黙的 using で System.Threading が入っているプロジェクトで
// using System.Timers; をファイルに書くと Timer が曖昧になる

// 原因: System.Threading.Timer と System.Timers.Timer の衝突
// 解決: .csproj で <Using Remove="System.Threading" /> するか
//       alias で明示的に区別する

// 「なぜか Timer が曖昧」と言われたら暗黙的 using を疑う
// → obj フォルダの *.GlobalUsings.g.cs を確認
落とし穴② — NuGet ライブラリに global using を入れてしまう
// NG: ライブラリプロジェクトの .csproj に ImplicitUsings=enable のまま
// → ライブラリ内部の global using は利用者に伝播しない(セーフ)

// 本当の問題: ライブラリの public API が暗黙的 using に依存する型を返す
// → 利用者が暗黙的 using を無効にしていると解決できない型が出る
// 例: ライブラリが Task<List<T>> を返す場合、利用者が
//     System.Collections.Generic を using していないとコンパイルエラー

// 推奨: ライブラリプロジェクトは ImplicitUsings=disable で明示的に using を書く
// → ライブラリ利用者の環境に依存しないコードになる
落とし穴③ — global using static の名前衝突
// global using static MyApp.Helpers.StringExt;
// global using static MyApp.Helpers.NumberExt;

// 両方に Format(this ...) という拡張メソッドがあると
// プロジェクト全ファイルで曖昧な呼び出しエラーになる

// 解決: global using static は「確実に重複しない」ものだけに限定
// Console / Math / Path など標準ライブラリの安定した型がベスト
落とし穴④ — global using を変更すると全ファイルに影響
// global using の追加は影響が小さいが
// 削除するとプロジェクト全ファイルでコンパイルエラーが出る可能性がある

// 安全に削除するには:
// 1. global using をコメントアウト
// 2. ビルド → エラーが出るファイルにローカル using を追加
// 3. 全エラー解消を確認してから global using の行を削除

// CI の「PR ビルドチェック」で検出できるので
// global using の変更は PR 経由で行うのが安全

よくある質問

QImplicitUsings を無効にすべきケースはありますか?
A①ライブラリプロジェクト(利用者環境を前提にしたくない)と、②「見えない using」が嫌でファイルに明示したいポリシーのチームでは無効化が合理的です。無効化すると SystemSystem.Linq 等をファイルごとに書く必要がありますが、「何がインポートされているか」がファイル単位で一目瞭然になるメリットがあります。新規プロジェクトではデフォルトの有効状態を維持し、global using で追加管理するのがシンプルです。
Qglobal using で追加すべき名前空間の基準は?
A「プロジェクト内のファイルの 80% 以上で使われている名前空間」が目安です。自作の ModelsServices 名前空間や、EF Core の Microsoft.EntityFrameworkCore、テストプロジェクトの XunitFluentAssertions などが典型です。逆に特定の処理でしか使わない名前空間(System.Security.Cryptography 等)はグローバル化せず、必要なファイルだけにローカル using を書いてください。
QC# 12 の any type alias は global using にできますか?
Aはい。global using Point = (int X, int Y); のように global を付けるとプロジェクト全体で使えます。タプル型・ジェネリック型・nullable 型にグローバルなエイリアスを付けることで、Dictionary<string, List<int>> のような長い型を短く書けます。ただしエイリアス名が他の型名と衝突しないよう注意してください。
Qglobal using と #nullable enable の関係は?
A直接的な関係はありません。#nullable enable はファイル単位またはプロジェクト単位(<Nullable>enable</Nullable>)で制御され、global using とは独立した機能です。ただし暗黙的 using + nullable enabled + file-scoped namespace を全部有効にすると、ファイル冒頭のボイラープレートがほぼ消え、ビジネスロジックに集中できるモダンな C# の書き方になります。
Qglobal using はソリューション全体に適用できますか?
Aいいえ。global using はプロジェクト(.csproj)単位の機能です。ソリューション内の複数プロジェクトで同じ global using を共有したい場合は、Directory.Build.props ファイルに <Using Include="..."/> を書く方法があります。リポジトリルートに置けばソリューション配下の全プロジェクトに適用されます。

まとめ

項目 ベストプラクティス
global using の管理 GlobalUsings.cs をプロジェクトルートに1ファイル
暗黙的 using デフォルト有効のまま使う。obj の .g.cs で確認
.csproj 制御 暗黙的 using の追加/削除に <Using> 要素を使う
C# 12 alias タプル・ジェネリック型にも alias 可能。global 付きで全体適用
global using static ConsoleMath など安全なもの限定。拡張メソッドの大量グローバル化は避ける
名前衝突 alias で区別するか <Using Remove> で除外
ライブラリ ImplicitUsings=disable で明示的に書く
テストプロジェクト XunitMoqFluentAssertions をグローバル化
file-scoped namespace global using と組み合わせてファイル冒頭のノイズを最小化
全プロジェクト共通 Directory.Build.props<Using> を共有

関連する機能は以下を参照してください。static 完全ガイドusing static の詳細、タプル完全ガイドで C# 12 の using エイリアスとタプル型の関係、本記事の内容はtarget-typed new 式と合わせてコードの冗長性を大幅に削減する C# 10 以降の主要機能です。