【问题标题】:Why isn't the new() generic constraint satisfied by a class with optional parameters in the constructor?为什么构造函数中带有可选参数的类不满足 new() 泛型约束?
【发布时间】:2010-04-30 17:25:01
【问题描述】:

以下代码编译失败,产生“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
    }
}

【问题讨论】:

  • 分页 Eric Lippert.... 我认为这将归结为可选参数是编译器功能,但通用约束是 CLR。因此编译器替换了可选参数,而 JIT 只看到(必需的)参数。
  • @Richard:这基本上就是这里的问题。由于这个原因,可选参数对版本控制也有一些奇怪的副作用......

标签: generics c#-4.0 optional-parameters


【解决方案1】:

虽然这在逻辑上应该有效,但不幸的是它没有。 CLR 仍将您的构造函数视为基于参数的构造函数。

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

public Widget(([Optional, DefaultParameterValue("foo")] string name) { // ...

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
       ) { // ... 

如果你在这里自动生成所有可能的组合,编译器需要为这个单一的构造函数生成 120 个构造函数,因为有 N!可能的调用方式...

【讨论】:

  • @Joshua:C# 编译器生成我上面粘贴的代码。这就是它的工作原理——它不是创建一个无参数的构造函数,而是一个可选的构造函数。我将编辑以添加详细信息...
  • 好的,谢谢,这就解释了为什么它不起作用。我仍然想知道生成无参数构造函数的含义是什么。
  • @Joshua:我编辑了我的答案来解释为什么这可能是一个坏主意......现在更有意义了吗?请记住,它不仅仅是可选的,您还可以使用命名参数,所以 N 个参数意味着 N!可能需要生成的组合...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
相关资源
最近更新 更多