2022-06-15に更新

【C#】あえて引数名を書くパターン

C# では、メソッドやコンストラクタに引数を渡す際に引数名を省略してコードを書く場合が多いと思いますが、明示的に引数名を書くこともできます。

int Add(int x, int y)
    => x + y;

// 引数名を省略する場合
var hoge = Add(10, 20);

// 引数名を明記する場合
var fuga = Add(x: 10, y: 20);

省略しても問題ない引数名を、わざわざ明記するパターンは以下のような場合が考えられます。

メソッドで定義している引数の順番とは違う順番で書ける

float Div(float x, float y)
    => x / y;

// x と y をメソッド定義とは異なる順番で渡す
Console.Write(Div(y: 2f, x: 1f));
// 0.5

とはいえ、何か特別な意図がない限りこういった使い方はしないと思います。

複数の省略可能引数(オプション引数)のうち一つを明示的に指定する

void Demo(int x, bool isHoge = false, bool isFuga = false, bool isPiyo = false)
{
    Console.WriteLine($"x: {x}");
    Console.WriteLine($"isHoge: {isHoge}");
    Console.WriteLine($"isFuga: {isFuga}");
    Console.WriteLine($"isPiyo: {isPiyo}");
}

// isHoge と isFuga はデフォルト値のまま、isPiyo のみ指定
Demo(10, isPiyo: true);

// x: 10
// isHoge: False
// isFuga: False
// isPiyo: True

// 名前付き引数を使用しない場合、すべての引数を明示的に指定する必要がある
Demo(10, false, false, true);

これも、元々のメソッドの設計があまり良くないなどの理由で、後付けで省略可能引数がわんさか付いているようなメソッドというのは古いコードではよくあります。

可読性の向上;「この引数でどうなるんだっけ?」対策

例として以下の StreamWriter の場合を考えてみます。

var path = GetPath();
using (var sw = new StreamWriter(path, flase))
    sw.Write("hoge");

StreamWriter のコンストラクタの第2引数に false を渡しています。この第2引数は append という引数名で定義されており、既にファイルが存在する場合に末尾に書き込むか、新しく上書きするかを真偽値で指定します1

ところが数年ぶりに StreamWriter を使ってこのコードを見た場合、この false がどういう作用をもたらすのか瞬時に理解できるでしょうか?

もちろん、IDE上で見る場合は引数の説明をいつでも参照することができます。そうでない場合でも、公式のリファレンスソースを参照することができることでしょう。この false が何をもたらすかというのは、数十秒あれば解決できる疑問かもしれません。

しかし、引数名を明記しておくと数十秒とかからず、コードを見ただけで瞬時に判断できるようになります。

var path = GetPath();
using (var sw = new StreamWriter(path, append: flase))
    sw.Write("hoge");

「この false の引数名、append ってことはこの場合追記じゃなくて上書きなのか」と、定義やドキュメントを参照するまでもなくコードを読んだ瞬間に意味を理解することができます。これはかなり大きなメリットなのではないでしょうか。

さらに、今回は StreamWriter を例に出しましたが、もしこれが公式のライブラリではなく、ドキュメントもろくにメンテされていない独自ライブラリだとしたらどうでしょう。「そのような環境の方が問題だろ!」というのももっともですが、しかし全てのドキュメントのメンテが行き届いている環境ばかりではありません。

個人的には、コメントに「falseは上書き」みたいなことを書くよりは、append: false と書いた方が余程良いと思います2


以上、個人的に想定する「引数名を明示する理由」をまとめてみました。

以下、おまけ。

最後のコメント的な用法に関しては、自作クラスを使う場合は WritingMode みたいな Enum を受け取るようにして、

using (var ow = OriginalWriter(path, WritingMode.Overwrite))
    ow.Write("hoge");

// WritingMode は
// WritingMode.Overwrite => 上書き
// WritingMode.Append    => 追記

という形で受け取るようにすれば、引数名を書かずとも「この引数では書込みモードを指定してますよ」という意図が明確になることもあります。自作する場合は、たとえ真偽値で判断できる場合でもあえて Enum を併用して、より意図を込めやすくなるように工夫できれば良いと思います。


  1. 参考 StreamWriter クラス|StreamWriter(String, Boolean)
    https://docs.microsoft.com/ja-jp/dotnet/api/system.io.streamwriter?view=net-6.0 ↩︎

  2. コメントが悪という主張ではなく、コードで表現できることは、できるだけコードで表現すべきという主張です。たとえば「なぜ追記じゃなくて上書きをするのか」という意図が共有してあるのは良いコメントだと感じます。 ↩︎

Originally published at boyi.sh
ツイッターでシェア
みんなに共有、忘れないようにメモ

あぱしょに

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント