为什么在构造函数中具有可选参数的类不满足new()泛型约束?

Jos*_*gan 5 generics optional-parameters c#-4.0

以下代码无法编译,产生"Widget必须是具有公共无参数构造函数的非抽象类型"错误.我认为编译器具有它需要的所有信息.这是一个错误吗?疏忽?或者是否存在某些无效的情况?

public class Factory<T> where T : new()
{
    public T Build()
    {
        return new T();
    }
}

public class Widget
{
    public Widget(string name = "foo")
    {
        Name = name;
    }

    public string Name { get; set; }
}

public class Program
{
    public static void Main()
    {
        var widget = new Widget(); // this is valid
        var factory = new Factory<Widget>(); // compiler error
    }
}
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 7

虽然这在逻辑上应该有效,但遗憾的是没有.CLR仍将构造函数视为基于参数的构造函数.

请记住,虽然C#支持可选参数,但这是在编译时在编译器级别完成的.底层类型仍然只包含一个带有单个参数的构造函数.就CLR而言,"默认参数"将转换为属性,如下所示:

public Widget(([Optional, DefaultParameterValue("foo")] string name) { // ...
Run Code Online (Sandbox Code Playgroud)

CLR是一种多语言运行时.对于所有语言,泛型都在CLR级别上工作,因此在没有默认参数的语言中,约束必须是正确的.理解OptionalAttribute和DefaultParameterValueAttribute不需要语言,因此这对于所有语言都不能统一工作,因此不允许使用.


编辑:

回应你的评论:

我不明白为什么C#编译器无法生成满足CLR的必要代码

从理论上讲,C#编译器团队可以使用该语言生成两个单独的构造函数,而不是一个标记有属性的构造函数.这可能会爆炸到许多构造函数中,因为命名参数会为"构造函数"(或方法的方法调用)的许多可能组合创建功能,尤其是在有多个参数可用时.我个人很高兴他们没有,因为它会因生成的类型中过多的方法和构造函数而导致混淆,这会导致公共API看起来与生成它的代码非常不同.采取以下构造函数:

public Widget(
          int id = 0, 
          string name = "foo", 
          float width=1.0f, 
          float height=1.0f, 
          float depth=1.0f
       ) { // ... 
Run Code Online (Sandbox Code Playgroud)

如果你在这里自动生成所有可能的组合,编译器需要为这个构造函数生成120个构造函数,因为有N!可以这样称呼这个......