C# Default Keyword: Syntax and Use Cases
c# default keyword: Learn how the C# default keyword works for value types, reference types, generics, and the default literal in modern C#.
The c# default keyword has two related forms: the default operator and the default literal. Both provide a way to obtain the default value of a type, but they serve different syntactic roles. Misunderstanding these forms leads to compile-time errors or subtle runtime bugs, especially in generic code.
The Default Operator for Value Types
For a value type, default(T) returns an instance where every field is set to its default value. For numeric types, that is zero; for bool, it is false; for char, it is \0; for enums, it is zero even if zero is not a defined enum member.
int number = default(int); // 0 bool flag = default(bool); // false char letter = default(char); // '\0' DayOfWeek day = default(DayOfWeek); // (DayOfWeek)0, which is Sunday
The expression default(int) is a compile-time constant, so it can be used in contexts that require constants, such as attribute arguments or switch case labels, although you would rarely need to do so.
Default Values for Reference Types
For reference types, default(T) returns null. This applies to classes, interfaces, delegates, and string.
string text = default(string); // null Stream stream = default(Stream); // null Action callback = default(Action); // null
This seems straightforward, but it becomes important when you have a variable that may or may not be assigned. Using default explicitly communicates intent compared to simply initializing with null.
The Default Literal in Modern C#
C# 7.1 introduced the default literal, which lets you omit the type when the compiler can infer it. The target type must be known at compile time.
int number = default; // equivalent to default(int) string text = default; // equivalent to default(string) MyClass obj = default; // null
The literal is especially useful with generics, where you want a fallback value without knowing the exact type.
Using Default with Generic Types
In a generic method or class, you often need to return a neutral value. The default keyword handles both value and reference types correctly.
public T GetDefault<T>() { return default(T); }
With the default literal, you can simplify this:
public T GetDefault<T>() { return default; }
But the literal only works when the target type is known. In the above method, T is known, so it compiles. For a Nullable<T>, default returns a Nullable<T> instance with no value, not null at the variable level.
Pitfalls and Common Mistakes
A frequent mistake is assuming default(T) for a Nullable<T> yields null in the same way as a reference type. In reality, default(int?) returns a Nullable<int> with HasValue == false. If you check for null using the == operator, it works syntactically, but you may encounter boxing or comparison oddities.
Another common error is using default in expression-bodied members without a clear target type. For example:
var result = default; // CS8773: Feature 'default literal' is not available
This fails because var does not provide a target type. You must specify the type.
Default in Conditional Expressions and Pattern Matching
The default literal can appear in conditional expressions when the other branch establishes the type.
object obj = condition ? "text" : default;
Here the compiler infers object because the second operand is the default value of object (null).
In pattern matching, default can be used in a switch expression or switch statement to match the default case.
string Describe(object value) => value switch { int i => $"Integer: {i}", string s => $"String: {s}", _ => "Unknown" };
Performance and Overhead Concerns
The default operator is a compile-time construct; it does not introduce runtime overhead. For value types, it is equivalent to initializing a struct with zeroed memory, which is already how many runtime operations allocate stack space. For reference types, it simply assigns null. There is no hidden cost.
One subtle performance consideration is in generic methods. When you call default(T), the JIT compiler can often optimize the return directly, especially for value types. For reference types, it is just a null assignment. There is no reason to avoid default for performance reasons; it is as efficient as writing null or 0 manually.
Compatibility and Language Version Notes
The default literal requires C# 7.1 or later. If you are targeting an older language version, you must use the default(T) operator. Most current projects compile with C# 9 or later, but if you maintain libraries for older compilers, you need to be aware of this constraint.
The behavior of default for value types is stable across all C# versions. The only difference is the syntactic shorthand. When using source generators or analyzers, the default literal may appear in generated code, and it is safe as long as the project's language version supports it.