C# 7.1 で導入された default リテラルを使用すると、型の既定値(デフォルト値)を記述する際に型名を省略できるようになりました。
これにより、メソッドのオプション引数(省略可能な引数)を定義する際、default(T) と記述していた冗長な表現を default だけで済ませることができ、コードがより読みやすくなります。特に構造体(DateTime や CancellationToken など)を引数に取る場合に有用です。
本記事では、ログ出力メソッドを題材に、default リテラルを活用したオプション引数の実装方法を解説します。
実装例:ログ出力メソッドでの活用
以下は、タイムスタンプ(DateTime)をオプション引数として受け取るログ出力機能の実装例です。引数が省略された場合、default キーワードによって DateTime 型の既定値が渡され、メソッド内部でそれを判定して現在時刻に置き換えています。
using System;
namespace DefaultLiteralExample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--- ログ出力テスト ---");
// 1. 引数を明示的に指定して呼び出し
// 指定した過去の日時でログが出力されます
var pastDate = new DateTime(2023, 1, 1, 12, 0, 0);
WriteLog("システムを起動しました。", pastDate);
// 2. 第二引数を省略して呼び出し
// 既定値 default が渡され、メソッド内で現在時刻に変換されます
WriteLog("処理を実行中です...");
}
/// <summary>
/// ログメッセージを出力します。
/// </summary>
/// <param name="message">メッセージ本文</param>
/// <param name="timestamp">日時(省略時は default = 0001/01/01 が入る)</param>
static void WriteLog(string message, DateTime timestamp = default)
{
// DateTimeの既定値(DateTime.MinValue)かどうかを判定
// 既定値であれば、現在時刻を代入する
if (timestamp == default)
{
timestamp = DateTime.Now;
}
Console.WriteLine($"[{timestamp:yyyy/MM/dd HH:mm:ss}] {message}");
}
}
}
解説
1. default リテラルの省略記法
以前のバージョン(C# 7.0 以前)では、オプション引数の既定値を設定する際に以下のように型を明記する必要がありました。
// 古い書き方
void WriteLog(string message, DateTime timestamp = default(DateTime)) { ... }
C# 7.1 以降では、コンパイラが左辺や文脈から型を推論できる場合、単に default と書くだけで済みます。
// 新しい書き方(推奨)
void WriteLog(string message, DateTime timestamp = default) { ... }
2. 既定値の振る舞いについて
default が返す値は型によって異なります。
- 参照型(クラス、stringなど):
null - 数値型(int, doubleなど):
0 - 構造体(DateTimeなど): メモリ上がすべてゼロの状態(
DateTimeの場合は0001/01/01 00:00:00)
構造体をオプション引数にする場合、null を許容しない(DateTime? ではなく DateTime を使う)設計では、メソッド内部で「既定値が渡されたかどうか」を == default で判定するパターンがよく使われます。
まとめ
default リテラルを使用することで、メソッドのシグネチャ(定義)を簡潔に保つことができます。
- 記述の簡素化:
default(T)をdefaultに短縮可能。 - 柔軟な引数設計: 構造体であっても、オプション引数として自然に扱える。
メソッドのオーバーロードを増やすことなく、柔軟な呼び出しに対応させるためのテクニックとして活用してください。
