Почему вы думаете, что новая строка ()
бесполезный и, например, новый int () не
бесполезно.
Давайте вернемся к основам и поговорим о ссылочных типах и типах значений.
Когда вы создаете int, long, point или что-то еще, тип значения выделяется в стеке - таким образом, int резервирует 4 байта в стеке, long - 8 байтов и так далее. Пространство стека, зарезервированное для типа значения, обнулено - невозможно сослаться на адрес типа значения в стеке и получить нулевое значение. Таким образом, конструкторы по умолчанию для типов значений, вероятно, являются скорее следствием причуд в распределении стека, чем полезностью (возможно, кто-то из MS мог бы дать больше понимания).
В любом случае я думаю, что System.String не хватает конструктора по умолчанию из-за паршивого дизайна API .
Неизменяемые объекты, в частности перечисляемые, почти всегда предоставляют конструктор по умолчанию для создания экземпляров пустой коллекции.
Я думаю, что у Microsoft были благие намерения: лучше использовать ""
или String.Empty
всякий раз, когда вам нужна пустая строка, потому что они интернированы, и не очень полезны для нового создания new String()
каждый раз, но мне кажется, что это способ Microsoft "спасти разработчиков от самих себя".
(Спасибо Microsoft, я ценю ваше патерналистское владение, но я вполне могу позаботиться о себе. Если я не хочу создавать несколько экземпляров одного и того же объекта, я кеширую его так же, как я сделать для bagillion других типов с конструктором по умолчанию.)
Сейчас вам нужно рассматривать объекты без конструкторов по умолчанию как особый случай из всего остального. Перепишите
public void DoSomething<T>() where T : new() { ... }
как два метода:
public void DoSomething<T>() where T : new() { DoSomething(() => new T()); }
public void DoSomething<T>(Func<T> constructor) { }
Клиенты вашего кода должны решить, какую функцию вызывать для себя.
Теперь кто-то, глядя на приведенный выше код, может спросить, почему вы передаете конструктор вместо фактического объекта в метод, т. Е.
public void DoSomething<T>(T obj) { ... }
Могут быть причины, например, если метод конструктора не гарантированно вызывается. Я работал над сложным приложением winform, в котором при нажатии кнопок или пунктов меню появлялась форма, или, если форма уже открыта, мы бы сфокусировались на ней. Итак, у нас было что-то вроде:
public T ShowForm<T>(Func<T> constructor) where T : Form
{
T res = default(T);
foreach(Form f in Application.OpenForms)
{
if (f is T)
{
res = (T)f;
break;
}
}
if (res == null)
res = constructor();
res.Focus();
return res;
}
Мы не могли использовать новое ограничение, так как некоторые формы имели конструкторы не по умолчанию, поэтому приведенная выше стратегия в конечном итоге сработала очень хорошо и избавила нас от необходимости создавать тонну фабричных классов.