Why can't the C# constructor infer type?

Why is type inference not supported for constructors the way it is for generic methods?

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>?

Though you could get around this with a factory class,

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

Is there a practical or philosophical reason why the constructor can't support type inference?

160
задан Robert Harvey 14 June 2013 в 17:50
поделиться

4 ответа

Есть ли философская причина, по которой конструктор не может поддерживать вывод типов?

Нет. Когда у вас есть

new Foo(bar)

, мы могли бы идентифицировать в области видимости все типы, называемые Foo, независимо от общей арности, а затем выполнять разрешение перегрузки для каждого, используя модифицированный алгоритм вывода типа метода. Затем нам нужно было бы создать алгоритм «улучшения», который определяет, какой из двух применимых конструкторов в двух типах, имеющих одинаковое имя, но разную общую арность , является лучшим конструктором. Чтобы поддерживать обратную совместимость, оператор неуниверсального типа всегда должен побеждать.

Есть ли практическая причина, по которой конструктор не может поддерживать вывод типа?

Да. Даже если выгода от функции перевешивает ее затраты - а они значительны - этого недостаточно для реализации функции. Эта функция должна быть не только чистой, но и большой чистой прибылью по сравнению со всеми другими возможными функциями, в которые мы могли бы инвестировать. Это также должно быть лучше, чем тратить это время и усилия по исправлению ошибок, работе над производительностью и другим возможным областям, в которые мы могли бы приложить эти усилия. И в идеале он должен хорошо вписываться в любую «тему» ​​релиза.

Кроме того, как вы правильно заметили, вы можете получить преимущества этой функции, фактически не имея самой функции, используя фабричный шаблон. Наличие простых обходных путей снижает вероятность того, что функция когда-либо будет реализована.

Эта функция уже давно входит в список возможных функций.Он никогда не был настолько высок в списке, чтобы его можно было реализовать.

ОБНОВЛЕНИЕ, март 2015 г.

Предлагаемая функция сделала его достаточно близко к началу списка для C # 6, чтобы быть специфицированным и разработанным, но затем была вырезана.

127
ответ дан 23 November 2019 в 21:33
поделиться

Конструктор должен иметь ту же общую спецификацию, что и сам класс. В противном случае было бы невозможно узнать, относится ли int в вашем примере к классу или к конструктору.

var obj = new MyType<int>(42);

Это будет класс MyType с конструктором MyType(int) или класс MyType с конструктором MyType(T) ?

1
ответ дан 23 November 2019 в 21:33
поделиться
public class MyType<T> 
{ 
   private readonly T field; 
   public MyType(T value) { field = value; } 
} 

могут, нет необходимости снова говорить конструктору, что такое T, поскольку вы уже сделали это в деклераторе класса.

также ваша фабрика неверна, вам нужно иметь открытый класс MyTypeFactory, а не просто открытый класс MyTypeFactory - если только вы не объявите фабрику внутри MyType class

Редактировать для обновления:

Ну, 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
ответ дан 23 November 2019 в 21:33
поделиться

Основная причина, по которой вывод универсального типа не может работать с конструкторами так, как вы хотите, заключается в том, что класс «MyType» даже не существует, когда все, что вы объявили, это «MyType». Помните, что разрешено иметь оба:

public class MyType<T> {
}

и

public class MyType {
}

Оба будут законны. Как бы вы устранили неоднозначность своего синтаксиса, если бы вы фактически объявили оба, и оба они объявили конфликтующий конструктор.

13
ответ дан 23 November 2019 в 21:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: