Introduced in C# 7.1, the default literal allows you to omit the type name when specifying the default value of a type.
This allows you to replace the verbose default(T) expression with a simple default when defining optional arguments for methods, making the code more readable. This is particularly useful when taking structures (such as DateTime or CancellationToken) as arguments.
In this article, I will explain how to implement optional arguments using the default literal, using a log output method as an example.
Table of Contents
- Implementation Example: Usage in a Log Output Method
- Explanation
- Summary
Implementation Example: Usage in a Log Output Method
Below is an implementation example of a logging function that accepts a timestamp (DateTime) as an optional argument. If the argument is omitted, the default value of the DateTime type is passed via the default keyword. The method then checks this and replaces it with the current time if necessary.
using System;
namespace DefaultLiteralExample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--- Log Output Test ---");
// 1. Call with explicit argument
// Logs are output with the specified past date
var pastDate = new DateTime(2023, 1, 1, 12, 0, 0);
WriteLog("System started.", pastDate);
// 2. Call omitting the second argument
// The default value is passed, and it is converted to the current time inside the method
WriteLog("Processing in progress...");
}
/// <summary>
/// Outputs a log message.
/// </summary>
/// <param name="message">Message body</param>
/// <param name="timestamp">Date and time (If omitted, default = 0001/01/01 is used)</param>
static void WriteLog(string message, DateTime timestamp = default)
{
// Check if it is the default DateTime value (DateTime.MinValue)
// If it is the default, assign the current time
if (timestamp == default)
{
timestamp = DateTime.Now;
}
Console.WriteLine($"[{timestamp:yyyy/MM/dd HH:mm:ss}] {message}");
}
}
}
Explanation
1. Shortened Syntax with the default Literal
In previous versions (C# 7.0 and earlier), you had to explicitly state the type when setting a default value for an optional argument, like this:
// Old style
void WriteLog(string message, DateTime timestamp = default(DateTime)) { ... }
In C# 7.1 and later, if the compiler can infer the type from the left-hand side or context, you simply need to write default.
// New style (Recommended)
void WriteLog(string message, DateTime timestamp = default) { ... }
2. Behavior of Default Values
The value returned by default depends on the type:
- Reference types (classes, strings, etc.):
null - Numeric types (int, double, etc.):
0 - Structs (DateTime, etc.): A state where memory is all zeros (For
DateTime, this is0001/01/01 00:00:00).
When using a structure as an optional argument, a common design pattern (if you are not using nullable types like DateTime?) is to check == default inside the method to determine if a value was passed.
Summary
By using the default literal, you can keep method signatures (definitions) clean and concise.
- Simplification: Shortens
default(T)todefault. - Flexible Design: Allows structures to be handled naturally as optional arguments.
Use this technique to support flexible method calls without increasing the number of method overloads.
