目标类型的 new 表达式Target-typed new expressions

  • [x] 建议[x] Proposed
  • [x] 原型[x] Prototype
  • [] 实现[ ] Implementation
  • [] 规范[ ] Specification

总结Summary

当类型已知时,不需要构造函数的类型规范。Do not require type specification for constructors when the type is known.

动机Motivation

允许字段初始化,而不复制类型。Allow field initialization without duplicating the type.

Dictionary<string, List<int>> field = new() {
    { "item1", new() { 1, 2, 3 } }
};

如果可从用法推断,则允许省略类型。Allow omitting the type when it can be inferred from usage.

XmlReader.Create(reader, new() { IgnoreWhitespace = true });

实例化对象,而不会对类型进行拼写检查。Instantiate an object without spelling out the type.

private readonly static object s_syncObj = new();

规范Specification

接受新的句法窗体,其中的 类型 为可选项 target_typed_new object_creation_expressionA new syntactic form, target_typed_new of the object_creation_expression is accepted in which the type is optional.

object_creation_expression
    : 'new' type '(' argument_list? ')' object_or_collection_initializer?
    | 'new' type object_or_collection_initializer
    | target_typed_new
    ;
target_typed_new
    : 'new' '(' argument_list? ')' object_or_collection_initializer?
    ;

Target_typed_new 表达式没有类型。A target_typed_new expression does not have a type. 但是,存在一个新的 对象创建转换 ,它是从表达式到每个类型的 target_typed_new 的隐式转换。However, there is a new object creation conversion that is an implicit conversion from expression, that exists from a target_typed_new to every type.

如果是的实例,则给定目标类型 T T0T 的基础类型 T System.NullableGiven a target type T, the type T0 is T's underlying type if T is an instance of System.Nullable. 否则 T0TOtherwise T0 is T. 转换为类型的 target_typed_new 表达式的含义与 T 指定为类型的相应 object_creation_expression 的含义相同 T0The meaning of a target_typed_new expression that is converted to the type T is the same as the meaning of a corresponding object_creation_expression that specifies T0 as the type.

如果 target_typed_new 用作一元运算符或二元运算符的操作数,或者如果在不受 对象创建转换 的情况下使用,则会发生编译时错误。It is a compile-time error if a target_typed_new is used as an operand of a unary or binary operator, or if it is used where it is not subject to an object creation conversion.

打开问题: 我们是否应允许委托和元组作为目标类型?Open Issue: should we allow delegates and tuples as the target-type?

上述规则包括 (引用类型) 和元组 (结构类型) 的委托。The above rules include delegates (a reference type) and tuples (a struct type). 尽管这两种类型都是可构造,但如果类型为 inferable,则可以使用匿名函数或元组文本。Although both types are constructible, if the type is inferable, an anonymous function or a tuple literal can already be used.

(int a, int b) t = new(1, 2); // "new" is redundant
Action a = new(() => {}); // "new" is redundant

(int a, int b) t = new(); // OK; same as (0, 0)
Action a = new(); // no constructor found

杂项Miscellaneous

下面是该规范的结果:The following are consequences of the specification:

  • throw new() (目标类型,则允许 System.Exception) throw new() is allowed (the target type is System.Exception)
  • new不允许将目标类型与二元运算符一起使用。Target-typed new is not allowed with binary operators.
  • 没有目标类型时,不允许这样做:一元运算符,在中的 foreach using 析构,在表达式中,作为匿名类型属性 () ,在语句中,在语句中,在语句中,在语句中,在语句中的 await new { Prop = new() } lock sizeof fixed 成员访问 (new().field) 中 someDynamic.Method(new()) is ?? ,作为运算符的操作数,在 LINQ (查询中,作为运算符的左操作数,.。。It is disallowed when there is no type to target: unary operators, collection of a foreach, in a using, in a deconstruction, in an await expression, as an anonymous type property (new { Prop = new() }), in a lock statement, in a sizeof, in a fixed statement, in a member access (new().field), in a dynamically dispatched operation (someDynamic.Method(new())), in a LINQ query, as the operand of the is operator, as the left operand of the ?? operator, ...
  • 它也不允许作为 refIt is also disallowed as a ref.
  • 不允许将以下类型作为转换的目标The following kinds of types are not permitted as targets of the conversion
    • 枚举类型: new() (为 new Enum()) 指定默认值,而 new(1) 不会起作用,因为枚举类型没有构造函数。Enum types: new() will work (as new Enum() works to give the default value), but new(1) will not work as enum types do not have a constructor.
    • 接口类型: 它的工作方式与 COM 类型对应的创建表达式相同。Interface types: This would work the same as the corresponding creation expression for COM types.
    • 数组类型: 数组需要一个特殊的语法来提供长度。Array types: arrays need a special syntax to provide the length.
    • 动态: 我们不允许 new dynamic() ,因此不允许 new() dynamic 作为目标类型。dynamic: we don't allow new dynamic(), so we don't allow new() with dynamic as a target type.
    • 元组: 它们与使用基础类型创建对象的含义相同。tuples: These have the same meaning as an object creation using the underlying type.
    • 还会排除 object_creation_expression 中不允许的所有其他类型,例如,指针类型。All the other types that are not permitted in the object_creation_expression are excluded as well, for instance, pointer types.

缺点Drawbacks

对于目标类型化 new 创建新类别的重大更改,存在一些问题,但我们已使用 null 和,但 default 这并不是一个重要问题。There were some concerns with target-typed new creating new categories of breaking changes, but we already have that with null and default, and that has not been a significant problem.

备选方法Alternatives

大多数关于字段初始化中太长时间的投诉都是关于类型 参数 ,而不是类型本身,我们只能推断 new Dictionary(...) (或类似) 类型参数,并在本地从参数或集合初始值设定项推断类型参数。Most of complaints about types being too long to duplicate in field initialization is about type arguments not the type itself, we could infer only type arguments like new Dictionary(...) (or similar) and infer type arguments locally from arguments or the collection initializer.

问题Questions

  • 是否应在表达式树中禁止使用情况?Should we forbid usages in expression trees? (no) (no)
  • 此功能如何与 dynamic 参数交互?How the feature interacts with dynamic arguments? (无特殊处理) (no special treatment)
  • IntelliSense 应如何操作 new()How IntelliSense should work with new()? 仅当存在单个目标类型时才 () (only when there is a single target-type)

设计会议Design meetings