Introduced in C# 9.0, Target-typed new expressions allow you to omit the type description when creating an instance and simply write new() provided the compiler can infer the type from the context.
Previously, code tended to become verbose when instantiating classes with long names or generic types. Using this feature reduces the amount of code and improves readability.
In this article, I will explain specific usage methods using a factory method that generates a configuration class for retry processing as an example.
Table of Contents
- Examples of Use
- Comparison with Previous Syntax
- Complete Implementation Code
- Use Cases and Benefits
- Summary
Examples of Use
The following code defines a RetryPolicy class that manages communication retry counts and intervals, and uses a target-typed new expression in the method that generates it.
Comparison with Previous Syntax
- Traditional (C# 8.0 and earlier): Even if the return type was fixed, you had to explicitly state the type name, like
return new RetryPolicy { ... }. - Current (C# 9.0 and later): Since the type can be inferred from the return type, you can write
return new() { ... }.
Complete Implementation Code
using System;
namespace NewExpressionExample
{
// Class to manage retry settings
public class RetryPolicy
{
// Retry count
public int MaxRetryCount { get; set; }
// Retry interval (milliseconds)
public int IntervalMilliseconds { get; set; }
public override string ToString()
{
return $"Retry Count: {MaxRetryCount}, Interval: {IntervalMilliseconds}ms";
}
}
class Program
{
static void Main(string[] args)
{
// 1. Use in method return values
// Since the type is clear from the method definition, new() can be used internally
RetryPolicy defaultPolicy = CreateDefaultPolicy();
Console.WriteLine("Default Settings: " + defaultPolicy);
// 2. Use in variable declaration
// Since the type is explicit on the left side, the right side only needs new()
RetryPolicy customPolicy = new()
{
MaxRetryCount = 5,
IntervalMilliseconds = 2000
};
Console.WriteLine("Custom Settings: " + customPolicy);
// Reference: When using var (Traditional type inference)
// Since the left side is inferred, the type is required on the right side
var legacyStyle = new RetryPolicy { MaxRetryCount = 1, IntervalMilliseconds = 500 };
}
// Factory Method
public static RetryPolicy CreateDefaultPolicy()
{
// Since it is clear that the return type is RetryPolicy,
// we can omit the type name and write new()
return new()
{
MaxRetryCount = 3,
IntervalMilliseconds = 1000
};
}
}
}
Use Cases and Benefits
Target-typed new expressions are particularly effective in the following situations:
- Field and Property Initialization:C#
private Dictionary<string, List<int>> _data = new();You avoid having to write long generic type names twice. - Method Arguments:C#
ProcessData(new() { Id = 1, Name = "Test" });If the type is determined by the method signature, you can omit the type name when creating and passing the object in the argument list. - Combination with Object Initializers: As shown in the example, when generating an object while setting properties, the area after
newbecomes cleaner, making it easier to focus on the setting values (properties).
Summary
The concise new() syntax is effective for reducing code noise. However, since it has an opposite relationship with the var keyword (explicit left side vs. explicit right side), it is good to have a policy within your team on which one to prioritize or how to use them depending on the situation.
Generally, it is recommended to actively use new() in places where the type is explicit, such as field definitions and method return values or arguments.
