new() 是编译器在左侧类型明确时省略右侧类型的合法简化写法,依赖变量声明、字段类型等上下文推断目标类型,不能与 var 共用,且不绕过泛型约束。

目标类型推断的 new 表达式不是语法糖,而是编译器在赋值左侧已知类型的前提下,主动省略右侧类型名的合法简化写法;它不改变语义、不引入运行时开销,但对上下文依赖极强——一旦左侧类型不明确或不可用,就会直接编译失败。
什么时候 new() 能成功推断类型
编译器必须能从变量声明、字段类型、方法返回值或泛型约束中唯一确定目标类型。常见有效场景包括:
- 局部变量声明时直接初始化:
StringBuilder sb = new(); - 字段初始化(C# 9+ 支持):
private readonly List<string> _items = new();</string> - 方法参数传递(需目标参数有明确类型):
void Process(List<int> list) { ... }; Process(new());</int> - 泛型方法调用中配合类型参数约束:
var result = CreateInstance<httpclient>();</httpclient>→ 若CreateInstance<t>() where T : new()</t>,则new()在内部可被接受
关键点:推断发生在「赋值/传参动作发生前」,且只看左侧是否提供足够类型信息,不看右侧构造函数是否存在重载。
new() 失败的典型错误现象
以下写法全部编译报错,错误信息通常是 Cannot infer the type of the new expression 或 There is no argument given that corresponds to the required parameter:
- 未声明变量类型就用
var+new():var x = new();——var本身需要右侧提供完整类型,而new()又依赖左侧,形成死锁 - 数组初始化中混用:
var arr = new[] { new(), new() };—— 编译器无法从多个new()推出统一元素类型 - 作为方法返回值但方法签名无泛型约束:
return new();在返回类型为object或dynamic的方法里不成立 - 调用带
params的重载方法:Log(new(), new());若Log(params object[])和Log(string, string)同时存在,编译器无法抉择
new() 与构造函数参数的兼容性
new() 并非只能调用无参构造函数。只要目标类型存在匹配的公开构造函数,编译器就会按需绑定:
-
StringBuilder sb = new("hello");→ 推断为StringBuilder,调用StringBuilder(string) -
Dictionary<int string> dict = new(10);</int>→ 推断为Dictionary<int string></int>,调用Dictionary<int string>(int)</int> - 但
Point p = new(3, 5);成立,是因为Point是record或支持目标类型推断的struct;普通 class 若只有Point(int x, int y)且无new()上下文,则仍需写全类型
注意:如果目标类型有多个构造函数,且参数类型模糊(如都接受 object),编译器可能因歧义报错,此时必须显式写出类型或改用具名参数。
和 var 混用时的真实限制
var 和 new() 本质冲突,不能共存于同一初始化表达式:
-
var sb = new();❌ 编译失败 ——var要求右侧能独立确定类型,而new()要求左侧提供类型 -
var sb = new StringBuilder();✅ 正常 —— 右侧已有完整类型,var只是别名 -
StringBuilder sb = new();✅ 正常 —— 左侧提供目标类型,启用目标推断
这个限制不是设计疏漏,而是类型系统逻辑闭环的必然结果:目标类型推断必须有“锚点”,而 var 恰好移除了这个锚点。
最易被忽略的一点:目标类型推断的 new 表达式在泛型类或方法内部行为不变,但若泛型参数本身未被约束(如 T t = new(); 且无 where T : new()),依然会失败——推断不绕过泛型约束检查。










