Почему конструктор С# не может вывести тип?

Почему вывод типа не поддерживается для конструкторов так, как это делается для общих методов?

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

Хотя вы можете обойти это с помощью класса factory,

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

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

Ответы

Ответ 1

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

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

new Foo(bar)

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

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

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

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

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

ОБНОВЛЕНИЕ Март 2015

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

Ответ 2

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

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

также ваш factory неверен, вам нужно иметь public class MyTypeFactory<T> не только public class MyTypeFactory - если вы не объявите factory внутри класса MyType

Изменить для обновления:

Ну, а 42 - длинный, короткий, 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);

Ответ 3

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

public class MyType<T> {
}

и

public class MyType {
}

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

Ответ 4

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

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

Будет ли это класс MyType<T> с конструктором MyType(int) или классом MyType с конструктором MyType<T>(T)?

Ответ 5

Несмотря на то, что это было ответино много раз раньше, я чувствую, что мне нужно прояснить одно: С# поддерживает общий тип вывода в конструкторах. Проблема в том, что она не поддерживает ни добавления общих параметров к конструкторам, ни типового вывода типа. Желание вывести общий тип аргумента самого типа в основном аналогично требованию Foo.Bar(0) сделать вывод Foo<int>.Bar(0).