C#の名前付き引数とは?使い方・省略可能な引数との違い・注意点をサンプルで解説
はじめに
C#でメソッドを呼び出すとき、通常は定義された引数の順番どおりに値を渡します。
C#CreateUser("Taro", 20, true);
この書き方は短くて便利ですが、引数が増えたり、true や false のような値が並んだりすると、後から読んだときに「この値は何を意味しているのか」がわかりにくくなることがあります。
そこで役立つのが名前付き引数です。
名前付き引数を使うと、引数名を明示して値を渡せます。
C#CreateUser(name: "Taro", age: 20, isActive: true);
このように書くことで、メソッド呼び出しだけを見ても、それぞれの値が何のためのものか判断しやすくなります。
この記事では、C#の名前付き引数について、基本的な使い方、位置指定引数との違い、省略可能な引数との違い、実務で役立つ場面、注意点、よくあるエラーまでサンプル付きで解説します。
1. C#の名前付き引数とは
C#の名前付き引数とは、メソッドやコンストラクターを呼び出すときに、引数名を指定して値を渡せる機能です。
通常のメソッド呼び出しでは、引数の順番に従って値が渡されます。一方、名前付き引数では、どの引数にどの値を渡すのかを名前で明示できます。
1-1. 引数名を指定してメソッドを呼び出す機能
たとえば、次のようなメソッドがあるとします。
C#void PrintUser(string name, int age)
{
Console.WriteLine($"{name}さんは{age}歳です。");
}
通常は次のように呼び出します。
C#PrintUser("Taro", 20);
名前付き引数を使うと、次のように書けます。
C#PrintUser(name: "Taro", age: 20);
name: "Taro" は、name という引数に "Taro" を渡すという意味です。
age: 20 は、age という引数に 20 を渡すという意味です。
このように、名前付き引数では 引数名: 値 の形式で指定します。
1-2. 通常の位置指定引数との違い
通常の引数指定は、位置指定引数と呼ばれます。
C#PrintUser("Taro", 20);
この場合、1番目の "Taro" は name に渡され、2番目の 20 は age に渡されます。
つまり、値がどの引数に対応するかは順番で決まります。
一方、名前付き引数では次のように書けます。
C#PrintUser(age: 20, name: "Taro");
この場合、順番は入れ替わっていますが、age と name を明示しているため、正しく値を渡せます。
位置指定引数は「順番」で値を決める書き方、名前付き引数は「名前」で値を決める書き方です。
1-3. 名前付き引数を使うとコードが読みやすくなる理由
名前付き引数を使う大きなメリットは、コードの意味がわかりやすくなることです。
次のコードを見てください。
C#SendMail("test@example.com", true, false);
この呼び出しだけを見ると、true と false が何を表しているのかわかりにくいです。
名前付き引数を使うと、次のように書けます。
C#SendMail(
address: "test@example.com",
isHtml: true,
requiresReply: false
);
このように書くと、true はHTMLメールとして送信するかどうか、false は返信が必要かどうかを表していると読み取れます。
特に bool 型の引数や、同じ型の引数が複数並ぶメソッドでは、名前付き引数を使うことで可読性が大きく向上します。
1-4. 名前付き引数が使える主な場面
名前付き引数は、主に次のような場面で使えます。
メソッド呼び出しで引数名を明示したい場合に使えます。
C#CalculatePrice(price: 1000, taxRate: 0.1);
コンストラクター呼び出しでも使えます。
C#var user = new User(name: "Taro", age: 20);
省略可能な引数と組み合わせて、一部の引数だけを指定することもできます。
C#CreateReport(title: "売上レポート", includeSummary: true);
また、ref や out を使うメソッドでも、名前付き引数を使うことができます。
C#int result;
int.TryParse(s: "123", result: out result);
ただし、名前付き引数は便利な反面、使い方を間違えるとコンパイルエラーになることがあります。基本ルールを理解して使うことが大切です。
2. C#の名前付き引数の基本的な使い方
ここからは、C#の名前付き引数の基本的な書き方をサンプルコードで確認していきます。
2-1. 名前付き引数の基本構文
名前付き引数の基本構文は次のとおりです。
C#メソッド名(引数名: 値);
複数の引数を指定する場合は、次のようにカンマで区切ります。
C#メソッド名(引数名1: 値1, 引数名2: 値2);
たとえば、次のようなメソッドがあるとします。
C#void ShowMessage(string message, int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(message);
}
}
名前付き引数を使って呼び出す場合は、次のように書きます。
C#ShowMessage(message: "Hello", count: 3);
message に "Hello"、count に 3 が渡されます。
2-2. メソッド呼び出しで名前付き引数を使うサンプル
次のサンプルでは、商品の合計金額を計算するメソッドを定義します。
C#int CalculateTotal(int price, int quantity)
{
return price * quantity;
}
通常の位置指定引数で呼び出すと、次のようになります。
C#int total = CalculateTotal(500, 3);
Console.WriteLine(total);
名前付き引数を使うと、次のように書けます。
C#int total = CalculateTotal(price: 500, quantity: 3);
Console.WriteLine(total);
出力結果はどちらも同じです。
C#1500
ただし、名前付き引数を使ったほうが、500 が価格、3 が数量であることが明確になります。
2-3. 引数の順番を入れ替えて指定する方法
名前付き引数を使うと、引数の順番を入れ替えて指定できます。
C#int total = CalculateTotal(quantity: 3, price: 500);
Console.WriteLine(total);
この場合も、price に 500、quantity に 3 が渡されるため、結果は同じです。
C#1500
位置指定引数では、順番を間違えると意味が変わってしまう場合があります。
C#int total = CalculateTotal(3, 500);
この場合は price に 3、quantity に 500 が渡されるため、意図と異なるコードになる可能性があります。
名前付き引数なら、順番を入れ替えても引数名で対応関係が決まるため、読みやすく安全に書けます。
2-4. 複数の名前付き引数を指定する方法
複数の名前付き引数は、次のようにカンマで区切って指定します。
C#void RegisterUser(string name, int age, string email)
{
Console.WriteLine($"名前: {name}");
Console.WriteLine($"年齢: {age}");
Console.WriteLine($"メール: {email}");
}
呼び出し側は次のように書けます。
C#RegisterUser(
name: "Taro",
age: 25,
email: "taro@example.com"
);
引数が多い場合は、1行にまとめるよりも複数行に分けると読みやすくなります。
C#RegisterUser(
email: "taro@example.com",
name: "Taro",
age: 25
);
名前付き引数を使えば、引数の順番よりも意味を重視してコードを読めます。
2-5. コンストラクターで名前付き引数を使う例
名前付き引数は、メソッドだけでなくコンストラクターにも使えます。
C#class User
{
public string Name { get; }
public int Age { get; }
public User(string name, int age)
{
Name = name;
Age = age;
}
}
通常の呼び出しは次のとおりです。
C#var user = new User("Taro", 20);
名前付き引数を使うと、次のように書けます。
C#var user = new User(name: "Taro", age: 20);
順番を入れ替えて指定することもできます。
C#var user = new User(age: 20, name: "Taro");
コンストラクターの引数が多い場合や、同じ型の引数が並ぶ場合は、名前付き引数を使うことで意図が伝わりやすくなります。
3. 位置指定引数と名前付き引数の違い
C#では、メソッド呼び出し時に位置指定引数と名前付き引数の両方を使えます。
それぞれの違いを理解しておくと、適切な書き方を選びやすくなります。
3-1. 位置指定引数は引数の順番で値が決まる
位置指定引数は、メソッド定義の引数の順番に従って値を渡す書き方です。
C#void SetSize(int width, int height)
{
Console.WriteLine($"幅: {width}, 高さ: {height}");
}
呼び出し側は次のように書きます。
C#SetSize(100, 200);
この場合、100 は width に、200 は height に渡されます。
位置指定引数は短く書けるため、引数が少なく意味が明確な場合に便利です。
C#Math.Max(10, 20);
このようなメソッドでは、名前付き引数を使わなくても意味がわかりやすいでしょう。
3-2. 名前付き引数は引数名で値が決まる
名前付き引数は、引数名を指定して値を渡す書き方です。
C#SetSize(width: 100, height: 200);
このように書くと、100 が幅、200 が高さであることがすぐにわかります。
順番を入れ替えても、引数名が正しければ問題ありません。
C#SetSize(height: 200, width: 100);
名前付き引数は、値の意味を明確にしたいときに便利です。
3-3. 位置指定引数と名前付き引数を混在させる書き方
位置指定引数と名前付き引数は、同じメソッド呼び出しの中で混在させることもできます。
C#void CreateAccount(string name, int age, bool isAdmin)
{
Console.WriteLine($"{name}, {age}, 管理者: {isAdmin}");
}
次のように、先に位置指定引数を書き、その後に名前付き引数を書くことができます。
C#CreateAccount("Taro", 30, isAdmin: false);
この場合、"Taro" は name、30 は age、false は isAdmin に渡されます。
よく使われる書き方としては、最初の必須引数は位置指定引数で短く書き、意味がわかりにくい引数だけ名前付き引数にする方法があります。
C#CreateAccount("Taro", 30, isAdmin: false);
特に bool 型の引数だけ名前付きにすると、コードが読みやすくなります。
3-4. 混在時にコンパイルエラーになる書き方
名前付き引数と位置指定引数を混在させる場合、書き方によってはコンパイルエラーになります。
たとえば、名前付き引数の後に、順番に合わない位置指定引数を書くとエラーになります。
C#CreateAccount(name: "Taro", 30, false);
このような書き方は避け、名前付き引数を使い始めた後は、以降の引数も名前付きで書くのが安全です。
C#CreateAccount(name: "Taro", age: 30, isAdmin: false);
または、位置指定引数を先に書いてから名前付き引数を書くようにします。
C#CreateAccount("Taro", 30, isAdmin: false);
基本的には、混在させる場合は「位置指定引数を先、名前付き引数を後」と覚えておくとよいでしょう。
3-5. どちらを使うべきかの判断基準
位置指定引数と名前付き引数のどちらを使うべきかは、コードの読みやすさで判断します。
引数が少なく、意味が明確な場合は位置指定引数で十分です。
C#Add(10, 20);
一方、引数の意味がわかりにくい場合は名前付き引数を使うとよいです。
C#SendMail(
to: "user@example.com",
isHtml: true,
requiresReply: false
);
また、同じ型の引数が複数並ぶ場合も、名前付き引数が役立ちます。
C#SetRange(start: 10, end: 100);
次のような基準で使い分けるとよいでしょう。
C#// 短くて意味が明確なら位置指定引数
Move(10, 20);
// 値の意味を明示したいなら名前付き引数
Move(x: 10, y: 20);
名前付き引数は必ず使うものではありません。読みやすさが上がる場面で使うのが基本です。
4. 省略可能な引数とは
C#の名前付き引数と一緒に理解しておきたい機能が、省略可能な引数です。
省略可能な引数とは、メソッド定義時にデフォルト値を指定することで、呼び出し時にその引数を省略できるようにする機能です。
4-1. 省略可能な引数の基本構文
省略可能な引数は、メソッド定義で引数にデフォルト値を指定します。
C#void メソッド名(型 引数名 = デフォルト値)
{
}
たとえば、次のように書きます。
C#void Greet(string name = "Guest")
{
Console.WriteLine($"こんにちは、{name}さん");
}
このメソッドは、name を指定して呼び出すことも、省略して呼び出すこともできます。
C#Greet("Taro");
Greet();
出力結果は次のようになります。
C#こんにちは、Taroさん
こんにちは、Guestさん
引数を省略した場合は、定義側で指定したデフォルト値が使われます。
4-2. デフォルト値を指定するサンプル
次の例では、ログを出力するメソッドに省略可能な引数を設定します。
C#void WriteLog(string message, string level = "INFO")
{
Console.WriteLine($"[{level}] {message}");
}
通常の呼び出しでは、message と level の両方を指定できます。
C#WriteLog("処理を開始しました", "DEBUG");
level は省略可能な引数なので、省略して呼び出すこともできます。
C#WriteLog("処理を開始しました");
この場合、level にはデフォルト値の "INFO" が使われます。
C#[INFO] 処理を開始しました
省略可能な引数を使うと、よく使う値を毎回指定しなくて済みます。
4-3. 省略できる引数と省略できない引数
省略可能な引数は、デフォルト値が設定されている引数です。
C#void CreateFile(string fileName, bool overwrite = false)
{
}
この例では、fileName は必須引数、overwrite は省略可能な引数です。
C#CreateFile("sample.txt");
CreateFile("sample.txt", true);
fileName はデフォルト値がないため、省略できません。
C#// コンパイルエラー
CreateFile();
また、通常は省略可能な引数は必須引数の後ろに定義します。
C#void Send(string to, string subject, bool isHtml = false)
{
}
必須引数を先に、オプション扱いの引数を後に置くことで、呼び出し側が自然に書けます。
4-4. 省略可能な引数を使うメリット
省略可能な引数のメリットは、メソッド呼び出しを簡潔にできることです。
たとえば、次のようなメソッドがあるとします。
C#void Print(string text, int count = 1, bool newLine = true)
{
for (int i = 0; i < count; i++)
{
if (newLine)
{
Console.WriteLine(text);
}
else
{
Console.Write(text);
}
}
}
通常は、最低限必要な引数だけで呼び出せます。
C#Print("Hello");
必要な場合だけ、追加の引数を指定できます。
C#Print("Hello", 3, false);
省略可能な引数を使うことで、呼び出し側のコードを短くしつつ、必要に応じて細かい設定もできるようになります。
4-5. 省略可能な引数だけでは対応しにくいケース
省略可能な引数は便利ですが、引数が多い場合や途中の引数だけを飛ばしたい場合には、位置指定引数だけでは書きにくくなります。
次のメソッドを見てください。
C#void Export(
string fileName,
string format = "csv",
bool includeHeader = true,
bool compress = false)
{
}
compress だけを true にしたい場合、位置指定引数だけで書くと、途中の引数も指定する必要があります。
C#Export("data", "csv", true, true);
このコードだけを見ると、最後の true が何を表しているのかわかりにくいです。
名前付き引数を使うと、次のように書けます。
C#Export(fileName: "data", compress: true);
このように、省略可能な引数と名前付き引数を組み合わせると、必要なオプションだけをわかりやすく指定できます。
5. 名前付き引数と省略可能な引数の違い
名前付き引数と省略可能な引数は一緒に使われることが多いため、混同されやすい機能です。
しかし、役割はまったく異なります。
名前付き引数は、呼び出し側で引数名を指定する機能です。
省略可能な引数は、定義側でデフォルト値を設定し、呼び出し側で引数を省略できるようにする機能です。
5-1. 名前付き引数は呼び出し側の書き方をわかりやすくする機能
名前付き引数は、メソッドを呼び出す側のコードを読みやすくするための機能です。
C#void Resize(int width, int height)
{
}
このメソッドは、省略可能な引数を持っていません。
それでも、名前付き引数を使って呼び出せます。
C#Resize(width: 800, height: 600);
つまり、名前付き引数は「引数を省略するための機能」ではありません。
あくまで、どの引数にどの値を渡しているのかを明示する機能です。
5-2. 省略可能な引数は引数を省略できるようにする機能
省略可能な引数は、メソッド定義側でデフォルト値を指定する機能です。
C#void Resize(int width = 800, int height = 600)
{
}
この場合、呼び出し側は引数を省略できます。
C#Resize();
デフォルト値を使わずに指定することもできます。
C#Resize(1024, 768);
省略可能な引数は、呼び出し側の記述を減らすために使います。
5-3. 名前付き引数と省略可能な引数を組み合わせるサンプル
名前付き引数と省略可能な引数は、組み合わせることで特に便利になります。
C#void CreateReport(
string title,
string format = "pdf",
bool includeSummary = false,
bool includeDetails = true)
{
Console.WriteLine($"タイトル: {title}");
Console.WriteLine($"形式: {format}");
Console.WriteLine($"概要: {includeSummary}");
Console.WriteLine($"詳細: {includeDetails}");
}
通常の呼び出しでは、必須引数だけを指定できます。
C#CreateReport("月次レポート");
名前付き引数を使えば、一部の省略可能な引数だけを指定できます。
C#CreateReport(
title: "月次レポート",
includeSummary: true
);
この場合、format はデフォルト値の "pdf"、includeDetails はデフォルト値の true が使われます。
5-4. 途中の省略可能な引数を飛ばして指定する方法
省略可能な引数が複数ある場合、途中の引数を飛ばして後ろの引数だけを指定したいことがあります。
C#void Upload(
string fileName,
string folder = "default",
bool overwrite = false,
bool notify = true)
{
}
notify だけを false にしたい場合、位置指定引数だけだと次のように書く必要があります。
C#Upload("sample.txt", "default", false, false);
しかし、名前付き引数を使えば、途中の引数を省略できます。
C#Upload(fileName: "sample.txt", notify: false);
この書き方なら、folder と overwrite はデフォルト値のまま、notify だけを変更できます。
省略可能な引数を多く持つメソッドでは、名前付き引数を使うことで、呼び出し側の意図が明確になります。
5-5. 名前付き引数と省略可能な引数の使い分け
名前付き引数と省略可能な引数は、次のように使い分けます。
名前付き引数は、値の意味をわかりやすくしたいときに使います。
C#SetSize(width: 800, height: 600);
省略可能な引数は、よく使う値をデフォルト化して、呼び出し側の記述を減らしたいときに使います。
C#SetSize(width: 800, height: 600, keepAspectRatio: true);
省略可能な引数と組み合わせると、一部のオプションだけを指定できます。
C#SetSize(width: 800, height: 600, keepAspectRatio: true);
名前付き引数は呼び出し側の可読性を高める機能、省略可能な引数は引数の指定を省略できるようにする機能です。
この違いを押さえておくと、混同せずに使えるようになります。
6. 名前付き引数が役立つ具体例
名前付き引数は、すべてのメソッド呼び出しで使う必要はありません。
しかし、特定の場面では非常に効果的です。
ここでは、C#の名前付き引数が役立つ具体例を紹介します。
6-1. bool型の引数に意味を持たせる
bool 型の引数は、名前付き引数と相性がよい代表例です。
次のコードを見てください。
C#SaveFile("data.txt", true);
この true が何を意味しているのか、メソッド定義を見ないとわかりません。
名前付き引数を使うと、意味が明確になります。
C#SaveFile(fileName: "data.txt", overwrite: true);
これなら、既存ファイルを上書きする指定だとすぐにわかります。
特に、true や false が複数並ぶメソッドでは、名前付き引数を使うと読みやすさが大きく変わります。
C#SendMail("user@example.com", true, false, true);
このようなコードは、値の意味がわかりにくくなります。
C#SendMail(
address: "user@example.com",
isHtml: true,
requiresReply: false,
highPriority: true
);
名前付き引数を使えば、それぞれの真偽値が何を表すのか明確になります。
6-2. 引数が多いメソッドを読みやすくする
引数が多いメソッドでは、位置指定引数だけだと読みにくくなることがあります。
C#CreateUser("Taro", "Yamada", 25, "Tokyo", true);
このコードでも動作はしますが、値が何を表しているのかすぐにはわかりません。
名前付き引数を使うと、次のように書けます。
C#CreateUser(
firstName: "Taro",
lastName: "Yamada",
age: 25,
address: "Tokyo",
isActive: true
);
引数が多い場合は、名前付き引数を使って複数行に分けると、コードレビューや保守のときに理解しやすくなります。
ただし、引数が多すぎるメソッドは設計そのものを見直したほうがよい場合もあります。
たとえば、設定値をまとめたクラスを作る方法もあります。
C#class UserOptions
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public int Age { get; set; }
public string Address { get; set; } = "";
public bool IsActive { get; set; }
}
名前付き引数は可読性を高める手段ですが、メソッド設計を改善する代わりになるわけではありません。
6-3. 一部のオプションだけを指定する
省略可能な引数が多いメソッドでは、一部のオプションだけを指定したいことがあります。
C#void Search(
string keyword,
int page = 1,
int pageSize = 20,
bool exactMatch = false,
bool includeDeleted = false)
{
}
includeDeleted だけを true にしたい場合、位置指定引数だと次のようになります。
C#Search("C#", 1, 20, false, true);
名前付き引数を使うと、必要な引数だけを指定できます。
C#Search(keyword: "C#", includeDeleted: true);
この書き方なら、page、pageSize、exactMatch はデフォルト値のまま、includeDeleted だけを変更できます。
オプションが多いメソッドでは、名前付き引数と省略可能な引数を組み合わせると、呼び出し側がすっきりします。
6-4. 同じ型の引数が並ぶ場合の指定ミスを防ぐ
同じ型の引数が複数並ぶメソッドでは、順番を間違えてもコンパイルエラーにならない場合があります。
C#void SetPeriod(DateTime startDate, DateTime endDate)
{
}
通常の位置指定引数では、次のように書きます。
C#SetPeriod(start, end);
しかし、誤って順番を逆にしても、どちらも DateTime 型なのでコンパイルは通ってしまいます。
C#SetPeriod(end, start);
名前付き引数を使うと、意図が明確になります。
C#SetPeriod(startDate: start, endDate: end);
同じ型の引数が並ぶ場合は、名前付き引数を使うことで指定ミスに気づきやすくなります。
文字列が複数並ぶ場合も同様です。
C#CreateAccount(userName: "taro", displayName: "Taro Yamada");
string 型の引数が多いメソッドでは、名前付き引数を積極的に使うと安全です。
6-5. APIやライブラリ呼び出しをわかりやすくする
APIやライブラリのメソッドでは、引数の意味を明確にしたい場面があります。
たとえば、次のようなメソッドを呼び出す場合です。
C#client.GetUsers(1, 50, true);
このコードだけでは、1、50、true の意味がわかりにくいです。
名前付き引数を使うと、次のように読みやすくなります。
C#client.GetUsers(
page: 1,
pageSize: 50,
includeInactive: true
);
外部ライブラリやチーム内共通ライブラリを使う場合、呼び出し側の可読性は重要です。
名前付き引数を使えば、メソッド定義を毎回確認しなくても、呼び出しコードから意図を読み取りやすくなります。
7. C#の名前付き引数を使うときの注意点
名前付き引数は便利ですが、使うときにはいくつか注意点があります。
特に、引数名の変更やオーバーロードとの組み合わせには気をつける必要があります。
7-1. 引数名を間違えるとコンパイルエラーになる
名前付き引数では、メソッド定義に存在する引数名を正しく指定する必要があります。
C#void PrintUser(string name, int age)
{
}
正しい呼び出しは次のとおりです。
C#PrintUser(name: "Taro", age: 20);
存在しない引数名を指定すると、コンパイルエラーになります。
C#// コンパイルエラー
PrintUser(userName: "Taro", age: 20);
このメソッドには userName という引数はありません。
名前付き引数では、メソッド定義側の引数名と完全に一致させる必要があります。
7-2. メソッド定義側の引数名変更が呼び出し側に影響する
名前付き引数を使っている場合、メソッド定義側の引数名を変更すると、呼び出し側に影響します。
たとえば、次のメソッドがあるとします。
C#void Send(string address)
{
}
呼び出し側では次のように名前付き引数を使っています。
C#Send(address: "test@example.com");
ここで、メソッド定義の引数名を email に変更します。
C#void Send(string email)
{
}
すると、既存の呼び出し側コードはエラーになります。
C#// コンパイルエラー
Send(address: "test@example.com");
名前付き引数を使う場合、引数名は呼び出し側から参照される名前になります。
特に public なメソッドやライブラリのAPIでは、引数名の変更が利用者に影響するため注意が必要です。
7-3. 使いすぎるとコードが冗長になる
名前付き引数は可読性を高めますが、すべての引数に使えばよいというものではありません。
たとえば、次のような単純なコードでは、名前付き引数を使わなくても十分わかりやすいです。
C#int result = Math.Max(10, 20);
これを次のように書くと、少し冗長に感じる場合があります。
C#int result = Math.Max(val1: 10, val2: 20);
もちろん間違いではありませんが、必ずしも読みやすくなるとは限りません。
名前付き引数は、値の意味がわかりにくい場合や、引数が多い場合に使うと効果的です。
C#CreateUser(name: "Taro", age: 20, isActive: true);
読みやすさが上がる場面で使うことが大切です。
7-4. オーバーロードとの組み合わせに注意する
C#では、同じ名前で引数の型や数が異なるメソッドを定義できます。これをオーバーロードと呼びます。
C#void Search(string keyword)
{
}
void Search(string keyword, int page)
{
}
名前付き引数を使う場合でも、オーバーロード解決は行われます。
C#Search(keyword: "C#");
Search(keyword: "C#", page: 2);
通常は問題ありませんが、似たような引数構成のオーバーロードが多いと、呼び出し側がわかりにくくなることがあります。
C#void SetValue(int value, bool save = false)
{
}
void SetValue(int value, string message = "")
{
}
このような設計では、名前付き引数や省略可能な引数を組み合わせたときに、どのメソッドが呼ばれるのか判断しづらくなることがあります。
オーバーロードと省略可能な引数を多用すると、呼び出し側の混乱につながるため注意しましょう。
7-5. public APIでは引数名も設計の一部として考える
private メソッドであれば、引数名を変更しても影響範囲は比較的小さいです。
しかし、public メソッドやライブラリとして公開するAPIでは、引数名も利用者が参照する可能性があります。
C#public void Download(string url, bool overwrite = false)
{
}
利用者は次のように呼び出すかもしれません。
C#Download(url: "https://example.com/file.zip", overwrite: true);
この場合、url や overwrite という引数名は、呼び出し側のコードに現れます。
後から引数名を変更すると、利用者のコードがコンパイルエラーになる可能性があります。
public APIでは、引数名もメソッド名や型と同じように、慎重に設計することが重要です。
8. 名前付き引数でよくあるエラーと対処法
名前付き引数を使い始めたときによくあるエラーを紹介します。
エラーの原因と対処法を知っておくと、スムーズに修正できます。
8-1. 名前付き引数の後に位置指定引数を書いている
よくあるエラーのひとつが、名前付き引数の後に位置指定引数を書いてしまうケースです。
C#void CreateUser(string name, int age, bool isActive)
{
}
次のような呼び出しはエラーになります。
C#// コンパイルエラー
CreateUser(name: "Taro", 20, true);
対処法は、すべて名前付き引数で書くことです。
C#CreateUser(name: "Taro", age: 20, isActive: true);
または、位置指定引数を先に書き、名前付き引数を後に書きます。
C#CreateUser("Taro", 20, isActive: true);
混在させる場合は、位置指定引数を先に書くのが基本です。
8-2. 存在しない引数名を指定している
メソッド定義に存在しない引数名を指定すると、コンパイルエラーになります。
C#void Login(string userName, string password)
{
}
次のコードでは、name という引数は存在しません。
C#// コンパイルエラー
Login(name: "taro", password: "password");
正しくは、メソッド定義に合わせて userName を指定します。
C#Login(userName: "taro", password: "password");
名前付き引数では、引数名のスペルミスにも注意が必要です。
C#// コンパイルエラー
Login(username: "taro", password: "password");
C#では大文字と小文字が区別されるため、userName と username は別の名前として扱われます。
8-3. 同じ引数を複数回指定している
同じ引数に対して、複数回値を指定するとコンパイルエラーになります。
C#void SetVolume(int volume)
{
}
次のようなコードはエラーです。
C#// コンパイルエラー
SetVolume(10, volume: 20);
volume に対して、位置指定引数で 10、名前付き引数で 20 を指定しているためです。
正しくは、どちらか一方だけを指定します。
C#SetVolume(10);
または、名前付き引数だけを使います。
C#SetVolume(volume: 20);
同じ引数を重複して指定しないように注意しましょう。
8-4. 必須引数を指定し忘れている
名前付き引数を使っていても、必須引数は省略できません。
C#void SendMessage(string to, string message, bool urgent = false)
{
}
このメソッドでは、to と message は必須引数です。
次のように message を省略するとコンパイルエラーになります。
C#// コンパイルエラー
SendMessage(to: "user@example.com", urgent: true);
正しくは、必須引数をすべて指定します。
C#SendMessage(
to: "user@example.com",
message: "確認をお願いします",
urgent: true
);
名前付き引数は、必須引数を省略する機能ではありません。
引数を省略できるのは、デフォルト値が設定された省略可能な引数だけです。
8-5. 省略可能な引数のデフォルト値を誤解している
省略可能な引数では、引数を省略したときにデフォルト値が使われます。
C#void PrintStatus(string message, string level = "INFO")
{
Console.WriteLine($"[{level}] {message}");
}
次の呼び出しでは、level に "INFO" が使われます。
C#PrintStatus(message: "処理完了");
ただし、名前付き引数を使ったからといって、指定していない必須引数まで自動で補われるわけではありません。
C#// コンパイルエラー
PrintStatus(level: "ERROR");
message は必須引数なので、省略できません。
また、省略可能な引数のデフォルト値は、メソッドを呼び出す側に埋め込まれる性質があります。
ライブラリで省略可能な引数のデフォルト値を変更した場合、利用側の再コンパイルが必要になるケースがあります。
公開APIで省略可能な引数を使う場合は、後からデフォルト値を変更する可能性も考えて設計しましょう。
9. 名前付き引数と関連機能の違い
C#には、名前付き引数と似た場面で使われる機能がいくつかあります。
ここでは、オーバーロード、params、ref・out、オブジェクト初期化子との違いを整理します。
9-1. 名前付き引数とオーバーロードの違い
オーバーロードとは、同じメソッド名で引数の型や数が異なるメソッドを複数定義する機能です。
C#void Print(string text)
{
Console.WriteLine(text);
}
void Print(string text, int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(text);
}
}
一方、名前付き引数は、メソッド呼び出し時に引数名を指定する機能です。
C#Print(text: "Hello", count: 3);
オーバーロードは「メソッド定義を複数用意する機能」です。
名前付き引数は「メソッド呼び出しをわかりやすくする機能」です。
役割が違うため、どちらが優れているというより、目的に応じて使い分けます。
9-2. 名前付き引数とparamsの違い
params は、可変長引数を定義するための機能です。
C#void PrintNumbers(params int[] numbers)
{
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}
呼び出し側では、複数の値をそのまま渡せます。
C#PrintNumbers(1, 2, 3);
名前付き引数は、引数名を指定して値を渡す機能です。
C#PrintNumbers(numbers: new int[] { 1, 2, 3 });
params は「個数が変わる引数を受け取る機能」です。
名前付き引数は「どの引数に値を渡しているかを明示する機能」です。
用途が異なるため、混同しないようにしましょう。
9-3. 名前付き引数とref・out引数の関係
ref や out を使う引数にも、名前付き引数を使えます。
out の例を見てみましょう。
C#int number;
bool success = int.TryParse(s: "123", result: out number);
このコードでは、s と result を名前付き引数として指定しています。
ref の場合も同様です。
C#void Increment(ref int value)
{
value++;
}
呼び出し側では、次のように書けます。
C#int count = 1;
Increment(value: ref count);
ref や out を使う場合も、名前付き引数の基本は同じです。
ただし、ref や out 自体の意味は変わりません。
名前付き引数は、あくまで呼び出し側で引数名を明示するための書き方です。
9-4. 名前付き引数とオブジェクト初期化子の違い
オブジェクト初期化子は、オブジェクトを生成するときにプロパティへ値を設定する機能です。
C#var user = new User
{
Name = "Taro",
Age = 20
};
一方、名前付き引数は、コンストラクターやメソッドの引数名を指定する機能です。
C#var user = new User(name: "Taro", age: 20);
両者は見た目が少し似ていますが、対象が違います。
名前付き引数は、メソッドやコンストラクターの引数に値を渡します。
オブジェクト初期化子は、生成したオブジェクトのプロパティやフィールドに値を設定します。
たとえば、次のようなクラスがあるとします。
C#class User
{
public string Name { get; set; } = "";
public int Age { get; set; }
public User()
{
}
public User(string name, int age)
{
Name = name;
Age = age;
}
}
名前付き引数を使う場合は、コンストラクターを呼び出します。
C#var user1 = new User(name: "Taro", age: 20);
オブジェクト初期化子を使う場合は、プロパティを設定します。
C#var user2 = new User
{
Name = "Taro",
Age = 20
};
コンストラクターで必須値を受け取りたい場合は名前付き引数、生成後にプロパティを設定したい場合はオブジェクト初期化子が使われることが多いです。
10. C#の名前付き引数に関するよくある質問
最後に、C#の名前付き引数についてよくある質問をまとめます。
10-1. 名前付き引数はいつから使える?
名前付き引数は、C# 4.0から利用できる機能です。
同じくC# 4.0では、省略可能な引数も導入されています。
そのため、現在のC#環境では基本的に利用できる機能と考えてよいでしょう。
ただし、非常に古いプロジェクトや古いコンパイラを使っている場合は、利用できる言語バージョンを確認してください。
10-2. 名前付き引数は必ず使ったほうがいい?
名前付き引数は便利ですが、必ず使う必要はありません。
引数が少なく、意味が明確な場合は位置指定引数で十分です。
C#Add(10, 20);
一方、値の意味がわかりにくい場合は名前付き引数を使うと読みやすくなります。
C#SendMail(address: "user@example.com", isHtml: true);
特に、bool 型の引数、同じ型の引数が並ぶメソッド、オプションが多いメソッドでは、名前付き引数を使うメリットがあります。
大切なのは、コードが読みやすくなる場面で使うことです。
10-3. 名前付き引数の順番は自由に変えられる?
名前付き引数は、基本的に順番を入れ替えて指定できます。
C#void SetSize(int width, int height)
{
}
次のどちらの書き方も可能です。
C#SetSize(width: 800, height: 600);
SetSize(height: 600, width: 800);
ただし、位置指定引数と混在させる場合は注意が必要です。
C#SetSize(800, height: 600);
このように、位置指定引数を先に書いてから名前付き引数を書くとわかりやすく安全です。
名前付き引数を使い始めた後に位置指定引数を書くとエラーになる場合があるため、混在させるときは書き方に注意しましょう。
10-4. 省略可能な引数なしでも名前付き引数は使える?
使えます。
名前付き引数は、省略可能な引数がある場合だけの機能ではありません。
次のように、すべて必須引数のメソッドでも名前付き引数を使えます。
C#void Move(int x, int y)
{
}
呼び出し側は次のように書けます。
C#Move(x: 10, y: 20);
このメソッドには省略可能な引数はありませんが、名前付き引数は問題なく使えます。
名前付き引数は、値を省略するためではなく、引数名を明示するための機能です。
10-5. 名前付き引数を使うと実行速度に影響はある?
通常、名前付き引数を使っても実行速度を気にする必要はありません。
名前付き引数は、主にコンパイル時に解決される呼び出し側の書き方です。
実行時に毎回、引数名を検索して処理するようなものではありません。
たとえば、次の2つは呼び出し方の見た目は違いますが、同じメソッドに値を渡しています。
C#SetSize(800, 600);
SetSize(width: 800, height: 600);
名前付き引数を使うかどうかは、実行速度ではなく、可読性や保守性を基準に判断するとよいでしょう。
まとめ
C#の名前付き引数は、メソッドやコンストラクターを呼び出すときに、引数名を指定して値を渡せる機能です。
通常の位置指定引数では、値がどの引数に対応するかは順番で決まります。一方、名前付き引数では、引数名で対応関係が決まります。
C#CreateUser(name: "Taro", age: 20, isActive: true);
名前付き引数を使うと、値の意味が明確になり、コードが読みやすくなります。
特に、次のような場面で役立ちます。
C#// bool型の意味を明確にする
SaveFile(fileName: "data.txt", overwrite: true);
// 同じ型の引数の指定ミスを防ぐ
SetPeriod(startDate: start, endDate: end);
// 省略可能な引数と組み合わせる
Export(fileName: "data.csv", compress: true);
省略可能な引数との違いも重要です。
名前付き引数は、呼び出し側で引数名を明示する機能です。
省略可能な引数は、定義側でデフォルト値を指定し、呼び出し側で引数を省略できるようにする機能です。
この2つを組み合わせることで、必要なオプションだけをわかりやすく指定できます。
ただし、名前付き引数を使う場合は、引数名の変更が呼び出し側に影響する点や、使いすぎると冗長になる点に注意が必要です。
C#の名前付き引数は、正しく使えばコードの可読性と保守性を高められる便利な機能です。引数の意味がわかりにくい場面や、省略可能な引数を一部だけ指定したい場面で、積極的に活用してみましょう。

