6

次のコードはコンパイルに失敗し、「ウィジェットはパブリックパラメーターなしのコンストラクターを持つ非抽象型でなければなりません」というエラーが発生します。コンパイラには必要な情報がすべて揃っていると思います。これはバグですか?見落とし?または、これが有効でないシナリオはありますか?

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
    }
}
4

1 に答える 1

9

これは論理的には機能するはずですが、残念ながら機能しません。CLRは、コンストラクターをパラメーターベースのコンストラクターと見なします。

C#はオプションのパラメーターをサポートしていますが、これはコンパイラレベルのコンパイル時に行われることに注意してください。基になる型には、単一のパラメーターを受け取るコンストラクターのみが含まれています。CLRに関する限り、「デフォルトパラメータ」は次のように属性に変換されます。

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

CLRは多言語ランタイムです。ジェネリックスは、すべての言語でCLRレベルで機能するように作成されているため、デフォルトのパラメーターがない言語でも制約が真である必要があります。オプション属性やDefaultParameterValueAttributeを理解するために言語は必要ないため、これはすべての言語で均一に機能するわけではないため、許可されていません。


編集:

あなたのコメントに応えて:

私が理解していないのは、C#コンパイラがCLRを満たすために必要なコードを生成できない理由です

理論的には、C#コンパイラチームは、属性でマークされた1つのコンストラクターではなく、2つの別個のコンストラクターを言語に生成させることができます。名前付きパラメーターは、特に複数の引数が使用可能な場合に、「コンストラクター」(またはメソッドのメソッド呼び出し)の多くの可能な組み合わせの機能を作成するため、これは潜在的に多くのコンストラクターに爆発します。生成された型のメソッドとコンストラクターが多すぎるために混乱が生じ、パブリックAPIがそれを生成したコードとは大きく異なって見えるため、これらが行われなかったことを個人的に嬉しく思います。次のコンストラクターを使用します。

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

ここで可能なすべての組み合わせを自動的に生成する場合、N個あるため、コンパイラーはこの単一のコンストラクターに対して120個のコンストラクターを生成する必要があります。これを呼び出すための可能な方法...

于 2010-04-30T17:30:32.870 に答える