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?
Есть ли философская причина, по которой конструктор не может поддерживать вывод типов?
Нет. Когда у вас есть
new Foo(bar)
, мы могли бы идентифицировать в области видимости все типы, называемые Foo, независимо от общей арности, а затем выполнять разрешение перегрузки для каждого, используя модифицированный алгоритм вывода типа метода. Затем нам нужно было бы создать алгоритм «улучшения», который определяет, какой из двух применимых конструкторов в двух типах, имеющих одинаковое имя, но разную общую арность , является лучшим конструктором. Чтобы поддерживать обратную совместимость, оператор неуниверсального типа всегда должен побеждать.
Есть ли практическая причина, по которой конструктор не может поддерживать вывод типа?
Да. Даже если выгода от функции перевешивает ее затраты - а они значительны - этого недостаточно для реализации функции. Эта функция должна быть не только чистой, но и большой чистой прибылью по сравнению со всеми другими возможными функциями, в которые мы могли бы инвестировать. Это также должно быть лучше, чем тратить это время и усилия по исправлению ошибок, работе над производительностью и другим возможным областям, в которые мы могли бы приложить эти усилия. И в идеале он должен хорошо вписываться в любую «тему» релиза.
Кроме того, как вы правильно заметили, вы можете получить преимущества этой функции, фактически не имея самой функции, используя фабричный шаблон. Наличие простых обходных путей снижает вероятность того, что функция когда-либо будет реализована.
Эта функция уже давно входит в список возможных функций.Он никогда не был настолько высок в списке, чтобы его можно было реализовать.
Предлагаемая функция сделала его достаточно близко к началу списка для C # 6, чтобы быть специфицированным и разработанным, но затем была вырезана.
Конструктор должен иметь ту же общую спецификацию, что и сам класс. В противном случае было бы невозможно узнать, относится ли int
в вашем примере к классу или к конструктору.
var obj = new MyType<int>(42);
Это будет класс MyType
с конструктором MyType(int)
или класс MyType
с конструктором MyType
?
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);
Основная причина, по которой вывод универсального типа не может работать с конструкторами так, как вы хотите, заключается в том, что класс «MyType» даже не существует, когда все, что вы объявили, это «MyType
public class MyType<T> {
}
и
public class MyType {
}
Оба будут законны. Как бы вы устранили неоднозначность своего синтаксиса, если бы вы фактически объявили оба, и оба они объявили конфликтующий конструктор.