web-dev-qa-db-ja.com

C#コンストラクターが型を推測できないのはなぜですか?

コンストラクターでは一般的なメソッドのように型推論がサポートされないのはなぜですか?

public class MyType<T>
{
   private readonly T field;
   public MyType(T value) { field = value; }
}

var obj = new MyType(42); // why can't type inference work out that I want a MyType<int>?

ファクトリクラスでこれを回避できますが、

public class MyTypeFactory
{
   public static MyType<T> Create<T>(T value)
   {
      return new MyType<T>(value);
   }
}
var myObj = MyTypeFactory.Create(42);

コンストラクターが型推論をサポートできない実用的または哲学的な理由はありますか?

155
theburningmonk

コンストラクターが型推論をサポートできないという哲学的な理由はありますか?

いいえ。

new Foo(bar)

次に、一般的なアリティに関係なく、スコープ内のFooと呼ばれるすべての型を識別し、修正されたメソッド型推論アルゴリズムを使用してそれぞれのオーバーロード解決を実行できます。次に、2つの適用可能なコンストラクターのいずれかを決定する「より良い」アルゴリズムを作成する必要があります同じ名前で一般的なアリティが異なる2つのタイプがより良いコンストラクターです。後方互換性を維持するために、非ジェネリック型のctorが常に勝たなければなりません。

コンストラクターが型推論をサポートできない実際的な理由はありますか?

はい。機能の利点がそのコストを上回る場合でも(かなり高い)、機能を実装するには十分ではありません。機能は純利益であるだけでなく、投資可能な他のすべての機能と比較して純利益である必要があります。また、その時間を費やすよりも優れている必要がありますバグ修正、パフォーマンス作業、およびその努力を注ぐことができるその他の可能な領域に関する努力。そして、理想的には、リリースの「テーマ」が何であれ、うまく適合する必要があります。

さらに、正しく指摘したように、ファクトリパターンを使用することにより、実際に機能自体を持たずにこの機能の利点を得ることができます。簡単な回避策が存在するため、機能が実装される可能性は低くなります。

この機能は、可能な機能のリストに長い間含まれています。実際に実装するのに十分なほどリストの高さの近くにあることはありません。

2015年3月更新

提案された機能により、C#6を指定および設計するためにリストの最上部に十分近づけられましたが、その後カットされました。

126
Eric Lippert
public class MyType<T> 
{ 
   private readonly T field; 
   public MyType(T value) { field = value; } 
} 

クラス宣言で既に行っているように、コンストラクタに「Tが何であるか」を再度伝える必要はありません。

また、工場が間違っているため、public class MyTypeFactory<T> だけでなく public class MyTypeFactory-MyTypeクラス内でファクトリを宣言しない限り

更新のために編集:

さて、42はlong、short、int、または他の何かですか?

次のものがあるとしましょう

class Base
{
   public virtual void DoStuff() { Console.WriteLine("Base"); }
}

class Foo : Base
{
   public override void DoStuff() { Console.WriteLine("Foo");  }
}

それからあなたはこれをしました

var c = new Foo();

var myType = new MyType(c);

fooの使用を期待しますか、それともbaseですか? Tの代わりに使用するものをコンパイラに指示する必要があります

タイプbaseを本当に使いたいとき

従って

var myType = new MyType<Base>(c);
18
PostMan

ジェネリック型推論が希望どおりにコンストラクターで機能しない主な理由は、宣言したすべてが「MyType <T>」である場合にクラス「MyType」が存在しないためです。両方を持つことは合法であることを忘れないでください:

public class MyType<T> {
}

および

public class MyType {
}

両方とも合法です。実際に両方を宣言し、それらの両方が競合するコンストラクターを宣言した場合、どのように構文を明確にしますか。

12
Kirk Woll

コンストラクターには、クラス自体と同じ汎用仕様が必要です。そうしないと、例のintがクラスに関連するのか、コンストラクタに関連するのかを知ることができません。

_var obj = new MyType<int>(42);
_

それは、コンストラクタMyType(int)を持つクラス_MyType<T>_またはコンストラクタMyType<T>(T)を持つクラスMyTypeでしょうか?

1
Albin Sunnanbo

これは以前にも何度も回答されてきましたが、私は1つのことを明確にする必要があると感じています:C#supportsコンストラクターのジェネリック型推論。問題は、ジェネリックパラメーターをコンストラクターに追加することも、typeジェネリック型推論もサポートしないことです。 type自体のジェネリック型引数を推測したいのは、Foo.Bar(0)を推測するためにFoo<int>.Bar(0)を要求するのと基本的に同じです。

0
IllidanS4