重载构造函数参数

Overloading constructor Params

考虑:

class MyList<T> {
  public MyList(params T[] ts) { /* add all items to internal list */ }
  public MyList(params IEnumerable<T>[] ets) { /* add all items from all enumerables to internal list */ }
}

然后

record Employee(string Name, int Age);

var l1 = new MyList<int>(1, 2, 3); // ok

IEnumerable<Employee> e = new List<Employee>() { new("John", 30), new("Eric", 30) };
var l2 = new MyList<Employee>(e, e); // ok

var l3 = new MyList<Employee>(
  new("John", 30),
  new("Eric", 30)
);

对于 l3 我得到:

The call is ambiguous between the following methods or properties: MyList<T>.MyList(params T[]) and MyList<T>.MyList(params IEnumerable<T>[])

我不明白为什么 l1 可以编译而 l3 不能编译?

有没有办法让这 3 个都起作用?

这与目标类型 new 的工作方式有关。从proposal开始,它具有以下特点:

A target_typed_new expression does not have a type. 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.

MyList 的构造函数的重载解析期间,它查看 new("John", 30)new("Eric", 30) 并发现存在从这些表达式到 EmployeeEmployee 的转换IEnumerable<Employee>,所以两种重载都适用,而且哪一种都更好。因此调用不明确。

从这个意义上说,它有点像 null 字面量或 default 字面量,我怀疑 l3 不起作用,原因与此类似不工作:

var l3 = new MyList<Employee>(
    default,
    default
);

不过,文档还说:

The following are consequences of the specification:

  • ...
  • The following kinds of types are not permitted as targets of the conversion
    • ...
    • Interface types: This would work the same as the corresponding creation expression for COM types.
    • ...

IEnumerable<Employee>是一个接口。

这表明“转换是否有效”是在重载解析之后进行的,这很奇怪。但接口是无效目标这一事实只是规范的“结果”,并没有明确指定(转换被指定为对所有类型有效,但由于target-typed new是一种对象创建表达式,你不能在对象创建表达式中使用接口) , 所以我想这在技术上没问题。