一、基本概念与语法
目标类型 new() (Target-typed new expression)是 C# 9.0 引入的核心语言特性,允许在目标类型已知的上下文 中省略 new 关键字后的类型名称,编译器会根据上下文自动推断要创建的对象类型。
核心语法对比
| 传统写法 | 目标类型 new() 写法 | 说明 |
|---|---|---|
List<int> list = new List<int>(); |
List<int> list = new(); |
无参构造函数 |
List<int> list = new List<int>(100); |
List<int> list = new(100); |
带参数构造函数 |
List<int> list = new List<int> { 1, 2, 3 }; |
List<int> list = new() { 1, 2, 3 }; |
对象/集合初始化器 |
Dictionary<string, List<int>> dict = new Dictionary<string, List<int>>(); |
Dictionary<string, List<int>> dict = new(); |
复杂泛型类型 |
关键规则
-
必须有明确目标类型 :不能在
var声明中使用new(),因为目标类型未知csharp// 错误:无法推断类型 // var list = new(); // 正确:目标类型明确 List<int> list = new(); -
适用场景:适用于所有有公共构造函数的引用类型和值类型(枚举除外)
-
完整语法形式:
antlrtarget_typed_new: 'new' '(' argument_list? ')' object_or_collection_initializer?;
二、解决的核心问题
1. 消除类型重复,提高代码简洁性
在复杂类型初始化时,无需重复冗长的类型名称,尤其适用于嵌套泛型类型:
csharp
// 传统写法
Dictionary<string, Dictionary<int, List<string>>> data =
new Dictionary<string, Dictionary<int, List<string>>>();
// 目标类型 new() 写法
Dictionary<string, Dictionary<int, List<string>>> data = new();
2. 简化字段与属性初始化
无需复制类型名称,使代码更易维护,减少拼写错误风险:
csharp
// 类中的字段初始化
private readonly Dictionary<string, List<LogEntry>> _logs = new()
{
["Error"] = new(),
["Warning"] = new(),
["Info"] = new()
};
3. 优化方法参数传递
当方法参数类型明确时,可直接使用 new() 创建实例:
csharp
// 方法定义
public void ProcessData(Options options) { ... }
// 调用方法(传统写法)
ProcessData(new Options { Timeout = 30, RetryCount = 3 });
// 调用方法(目标类型 new() 写法)
ProcessData(new { Timeout = 30, RetryCount = 3 });
4. 支持 throw 语句中的异常创建
csharp
// 目标类型为 System.Exception
throw new();
// 带参数的异常
throw new("Invalid operation", innerException);
三、生产环境使用场景
1. 集合与复杂对象初始化(最常用)
在业务逻辑中创建各种集合类型,尤其是在配置初始化、数据缓存等场景:
csharp
// 配置初始化
var appSettings = new AppSettings
{
ConnectionStrings = new()
{
["Default"] = "Server=...",
["Redis"] = "localhost:6379"
},
Logging = new()
{
LogLevel = new()
{
["Default"] = LogLevel.Information,
["Microsoft"] = LogLevel.Warning
}
}
};
2. 依赖注入配置
在 ASP.NET Core 等框架中配置服务时,简化选项初始化:
csharp
// Startup.cs 或 Program.cs
builder.Services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new() // 推断为 ServiceFilterAttribute
{
ServiceType = typeof(ValidationFilter)
});
});
3. 数据传输对象(DTO)创建
在 API 开发中创建请求/响应对象,减少重复代码:
csharp
// 创建订单请求
var createOrderRequest = new CreateOrderRequest
{
CustomerId = "CUST-123",
Items = new()
{
new() { ProductId = "PROD-456", Quantity = 2, UnitPrice = 19.99m },
new() { ProductId = "PROD-789", Quantity = 1, UnitPrice = 49.99m }
},
ShippingAddress = new()
{
Street = "123 Main St",
City = "Seattle",
State = "WA",
PostalCode = "98101"
}
};
4. 单元测试中的对象构建
在测试代码中快速创建测试数据,提高可读性:
csharp
[Test]
public void CalculateTotal_WithDiscount_ReturnsCorrectValue()
{
// Arrange
var order = new Order
{
Id = 1,
CustomerId = "CUST-123",
Items = new()
{
new() { ProductName = "Laptop", Price = 999.99m, Quantity = 1 },
new() { ProductName = "Mouse", Price = 29.99m, Quantity = 2 }
},
Discount = new() // 推断为 PercentageDiscount
{
Rate = 0.1m // 10% 折扣
}
};
// Act
var total = order.CalculateTotal();
// Assert
Assert.AreEqual(999.99m + 29.99m*2-(999.99m + 29.99m*2)*0.1m, total);
}
5. 事件与委托处理
在注册事件处理程序时,简化委托实例创建:
csharp
// 声明事件
public event EventHandler<DataReceivedEventArgs> DataReceived;
// 触发事件(传统写法)
DataReceived?.Invoke(this, new DataReceivedEventArgs(data));
// 触发事件(目标类型 new() 写法)
DataReceived?.Invoke(this, new(data));
6. 不可变类型与记录(Record)初始化
C# 9.0+ 中的记录类型结合目标类型 new(),使不可变对象创建更简洁:
csharp
public record Person(string FirstName, string LastName, int Age);
// 创建记录实例
Person person = new("John", "Doe", 30);
// 使用 with 表达式创建新实例
Person updatedPerson = person with { Age = 31 };
四、完整可运行代码示例
以下是一个包含多种场景的完整示例,可直接在 C# 9.0+ 环境中运行:
csharp
using System;
using System.Collections.Generic;
using System.Linq;
// 1. 简单类型与集合初始化
void BasicUsage()
{
Console.WriteLine("=== 基本用法 ===");
// 列表初始化
List<string> fruits = new() { "Apple", "Banana", "Cherry" };
Console.WriteLine($"Fruits: {string.Join(", ", fruits)}");
// 字典初始化
Dictionary<int, string> numberNames = new()
{
[1] = "One",
[2] = "Two",
[3] = "Three"
};
Console.WriteLine($"Number 2: {numberNames[2]}");
// 带参数构造函数
List<int> numbers = new(10); // 初始容量为 10
numbers.AddRange(Enumerable.Range(1, 5));
Console.WriteLine($"Numbers count: {numbers.Count}, Capacity: {numbers.Capacity}");
}
// 2. 嵌套复杂对象
void NestedObjects()
{
Console.WriteLine("\n=== 嵌套对象 ===");
var company = new Company
{
Name = "Tech Corp",
Departments = new()
{
new()
{
Name = "Engineering",
Employees = new()
{
new() { Id = 1, Name = "Alice", Position = "Developer" },
new() { Id = 2, Name = "Bob", Position = "Designer" }
}
},
new()
{
Name = "Sales",
Employees = new()
{
new() { Id = 3, Name = "Charlie", Position = "Sales Manager" }
}
}
}
};
Console.WriteLine($"Company: {company.Name}");
foreach (var dept in company.Departments)
{
Console.WriteLine($" Department: {dept.Name}");
foreach (var emp in dept.Employees)
{
Console.WriteLine($" - {emp.Name} ({emp.Position})");
}
}
}
// 3. 方法参数与异常处理
void MethodParametersAndExceptions()
{
Console.WriteLine("\n=== 方法参数与异常 ===");
// 方法参数传递
ProcessOrder(new()
{
OrderId = "ORD-789",
Items = new()
{
new() { ProductId = "PROD-100", Quantity = 2 }
}
});
// 异常抛出
try
{
ValidateOrder(null);
}
catch (ArgumentNullException ex)
{
Console.WriteLine($"Caught expected exception: {ex.Message}");
}
}
// 辅助类定义
public class Company
{
public string Name { get; set; } = string.Empty;
public List<Department> Departments { get; set; } = new();
}
public class Department
{
public string Name { get; set; } = string.Empty;
public List<Employee> Employees { get; set; } = new();
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Position { get; set; } = string.Empty;
}
public class Order
{
public string OrderId { get; set; } = string.Empty;
public List<OrderItem> Items { get; set; } = new();
}
public class OrderItem
{
public string ProductId { get; set; } = string.Empty;
public int Quantity { get; set; }
}
// 辅助方法
public static void ProcessOrder(Order order)
{
Console.WriteLine($"Processing order: {order.OrderId}");
foreach (var item in order.Items)
{
Console.WriteLine($" Product {item.ProductId}: {item.Quantity} units");
}
}
public static void ValidateOrder(Order? order)
{
if (order == null)
throw new ArgumentNullException(nameof(order), "Order cannot be null");
}
// 主程序
public class Program
{
public static void Main()
{
BasicUsage();
NestedObjects();
MethodParametersAndExceptions();
}
}
代码运行结果
=== 基本用法 ===
Fruits: Apple, Banana, Cherry
Number 2: Two
Numbers count: 5, Capacity: 10
=== 嵌套对象 ===
Company: Tech Corp
Department: Engineering
- Alice (Developer)
- Bob (Designer)
Department: Sales
- Charlie (Sales Manager)
=== 方法参数与异常 ===
Processing order: ORD-789
Product PROD-100: 2 units
Caught expected exception: Order cannot be null (Parameter 'order')
四、最佳实践与注意事项
1. 适用与不适用场景对比
| 推荐使用场景 | 不推荐/不适用场景 |
|---|---|
| 字段/属性初始化,尤其是复杂类型 | 使用 var 声明变量时 |
| 方法参数传递(类型明确) | 枚举类型(无构造函数) |
异常抛出(throw new()) |
接口类型(无法直接实例化) |
| 集合初始化(List、Dictionary 等) | 数组创建(需要特殊语法) |
| 嵌套对象创建 | 动态类型(dynamic) |
2. 与 var 的区别
| 特性 | 目标类型 new() | var |
|---|---|---|
| 类型推断方式 | 从目标类型推断 | 从右侧表达式推断 |
| 适用场景 | 目标类型明确时 | 右侧类型明确时 |
| 语法形式 | Type variable = new(); |
var variable = new Type(); |
| 可读性 | 类型在左侧,一目了然 | 类型在右侧,需查看 |
3. 版本兼容性
-
目标类型 new() 是 C# 9.0 及以上版本 的特性
-
若需在旧版本项目中使用,需升级项目的语言版本:
xml<!-- .csproj 文件 --> <PropertyGroup> <LangVersion>9.0</LangVersion> </PropertyGroup>
五、总结
目标类型 new() 是 C# 语言的重要改进,它通过上下文类型推断消除了重复的类型名称,使代码更加简洁、易读和易维护。在生产环境中,它特别适合集合初始化、复杂对象创建、方法参数传递等场景,能显著提高开发效率并减少错误。
核心价值:在保持类型安全的前提下,平衡了代码简洁性与可读性,是现代 C# 开发中不可或缺的语法糖。