Почему конструктор C # не может определить тип? - PullRequest
155 голосов
/ 26 августа 2010

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

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);

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

Ответы [ 5 ]

123 голосов
/ 26 августа 2010

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

Нет.Если у вас есть

new Foo(bar)

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

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

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

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

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

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

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

18 голосов
/ 26 августа 2010
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);
12 голосов
/ 26 августа 2010

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

public class MyType<T> {
}

и

public class MyType {
}

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

1 голос
/ 26 августа 2010

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

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

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

0 голосов
/ 12 ноября 2014

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

...