Подтвердить что ты не робот

System.String - почему он не реализует беззазорный конструктор?

Я хотел спросить, в чем заключается идея того, что System.String не содержит конструктора без параметров.

Из-за этого вы не можете использовать этот тип, если существует ограничение new().

UPDATE

Почему вы думаете, что новая строка() бесполезна и, например, new int() не бесполезен. Я действительно не вижу разницы. Я действительно хотел бы иметь возможность использовать ограничение new() для строки, поскольку я ожидаю, что это String.Empty.

UPDATE2

Я знаю, что int - это тип значения, а все типы значений имеют конструктор без параметров без параметров. Я имел в виду @John Saunders ответ (и аналогичные ответы), которые заявляли, что высказывание нового String() в основном не делает ничего полезного. Итак, если новый String() не означает ничего полезного, что так полезно для нового int()? Я также понимаю, что для типов значений важно иметь конструкторы без параметров без параметров. Более того, я думаю, что было бы очень хорошо, если бы строка имела конструктор без параметров без параметров. Отсутствие безпараметрического конструктора означает, что объект просто не может существовать без параметра, который его инициализирует. По-моему, строка не нуждается ни в каком параметре, потому что она может быть пустой. Я задал этот вопрос, потому что хотел узнать, есть ли какая-то важная причина для строки, не имеющей конструктора без параметров, или просто проектирования или другого.

Update3

Я предполагаю, что это будет последнее обновление, поскольку оно больше похоже на сообщение в блоге, чем на вопрос. В java-строках также неизменяемы, и новый String() совершенно легален. Однако документация для конструктора без параметров говорит:

Инициализирует вновь созданную строку объект, чтобы он представлял пустой последовательность символов. Обратите внимание, что использование этот конструктор не нужен, поскольку Строки неизменяемы.

UPDATE4

Хорошо, последнее обновление;) Я должен согласиться с Джоном Сондерсом. Я использовал код, у которого было ограничение new(), и оно отлично работало для пользовательских классов. Затем моему коллеге нужно изменить код для ints, и все в порядке. Затем измените его на строку, и у нас возникла проблема. Когда я сейчас думаю об этом, я думаю, что используемый нами код нуждается в изменении, чтобы отразить, что нам нужны скалярные типы, а не классы, у которых нет конструктора без параметров. Все, что сказал, я все еще думаю, что это немного несовместимо с тем, что вы можете написать новый int(), и вы не можете написать новую строку() (да, я понимаю, что int - тип значения;)). Спасибо за все ваши ответы!

Заранее благодарим за помощь.

4b9b3361

Ответ 1

Если вы можете использовать

string s = new string();

Что бы вы сделали с этим? Строки неизменяемы.


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

Имейте в виду, что OP сказал, что он хотел сделать:

public void SomeMethod<T>() where T : new()
{
    var t = new T();
    // Do _what_ now?
}

// Call:
SomeMethod<string>();

Я не вижу, что вы могли бы сделать с t после его создания.

Ответ 2

Почему вы думаете, что новая строка() бесполезно и, например, new int() не бесполезно.

Вернемся к основам и поговорим о типах ссылок и значениях.

Когда вы создаете int, long, point или что-то другое, тип значения выделяется в стеке, поэтому int сохраняет 4 байта в стеке, длиной 8 байт и так далее. Объем стека, зарезервированный для типа значения, равен нулю - его невозможно когда-либо ссылаться на адрес типов значений в стеке и получить нуль. Таким образом, конструкторы по умолчанию для типов значений, вероятно, приводят больше от причуд в распределении стека, чем полезности (возможно, кто-то из MS мог бы дать больше понимания).

В любом случае, я считаю, что System.String не имеет конструктора по умолчанию из-за конструктивного дизайна API.

Неизменяемые объекты - перечисляемые в частности - почти всегда выставляют конструктор по умолчанию для создания пустой коллекции.

Я думаю, что у Microsoft были хорошие намерения: лучше использовать "" или String.Empty всякий раз, когда вам нужна пустая строка, потому что они интернированы и не так полезны для нового a new String() каждый раз - но это приходит мне на ум как способ "спасти разработчиков от самих себя".

(Спасибо, 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;
}

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

Ответ 3

Я предполагаю, что вы хотите определить класс, что-то вроде этого:

public class SpecializedCollection<T> where T : new() {
    private List<T> _startingItems;

    public SpecializedCollection(int startingSize) {
        _startingItems = new List<T>(startingSize);
        for (int i = 0; i < startingSize; ++i)
            _startingItems.Add(new T());
    }

    // ... lots more code
}

Я прав? Если вы хотите, чтобы это было более гибким, чтобы разрешить типы, у которых не может быть конструктор без параметров без параметров, вы всегда можете сделать это:

public class SpecializedCollection<T> {
    private List<T> _startingItems;

    // note: here we leave it up to the caller to specify
    // how T objects will be instantiated
    public SpecializedCollection(int startingSize, Func<T> generator) {
        _startingItems = new List<T>(startingSize);
        for (int i = 0; i < startingSize; ++i)
            _startingItems.Add(generator.Invoke());
    }
}

Тогда вы можете создать SpecializedCollection<string> так:

var strings = new SpecializedCollection<string>(10, () => string.Empty);

Конечно, если вы хотите предложить конструктор по умолчанию, который попытается построить объекты с помощью конструктора без параметров для T, вы всегда можете перегрузить конструктор:

public SpecializedCollection(int startingSize)
    : this(startingSize, Activator.CreateInstance<T>()) { }

Вышеупомянутое не будет работать для string, конечно, но это будет для любого класса с безпараллельным конструктором (т.е. что-нибудь, что бы работало со старым ограничением where T : new()).

Ответ 4

Что такое строка без фактической строки?

Вы можете сделать это:

  String s = "hello world";

И как только у вас есть строка, вы не можете изменить эту конкретную строку (strimgs неизменяемы). Если вы хотите объявить пустую строку, просто выполните:

string s = string.empty

Ответ 5

Это общая проблема в общем коде. С++ решает его с помощью специализации шаблонов, но С# не поддерживает это.

Это невозможно сделать на С#, но лучше всего использовать ограничение class вместо этого, а затем использовать взломанную на основе поиска конструкцию a T или использовать String.Empty, если T есть System.String. Вы потеряете проверку компилятора для использования других классов, которые по умолчанию не являются конструктивными.

Вот еще один вариант:

class MyClass<T> where T : class
{
    public MyClass(T default)
    private T m_default;      
};

MyClass<object> instance = new MyClass<object>(new object());
MyClass<string> instance = new MyClass<string>(String.Empty);

И еще:

class MyClass<T> where T : class
{
    static SetDefault(T def)
    { 
       s_default = def;
    }
    static T s_default;      
};

MyClass<object> instance = new MyClass<object>(new object());
MyClass<string> instance = new MyClass<string>(String.Empty);

Ответ 6

"[Почему не] System.String... содержит конструктор [a] без параметров?"

Потому что так оно и было спроектировано. Как вы можете видеть из множества ответов и мнений здесь, нет даже четкого консенсуса в отношении необходимости или реализации конструктора без параметров. Очевидно, что технически возможно иметь конструктор по умолчанию, который инициализируется до String.Empty - поэтому либо команда BCL не думала об этом (маловероятно), либо не чувствовала, что это был достойный сценарий (вероятно). FWIW, я согласен - я не вижу причины, по которой важно значение ctor по string.

"Почему вы думаете, что новая строка() бесполезна и, например, новый int() не бесполезен, я действительно не вижу разницы".

Разница в том, что int является ValueType. ValueType требуется, чтобы иметь конструктор по умолчанию, и он инициализирует тип значением по умолчанию. string является ссылочным типом - он уже имеет значение по умолчанию - null (так же, как и все другие ссылочные типы).

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

E: Почему примитивная одержимость?

Я собирался писать об ORM или других картографах (несколько полезных мест, которые я могу придумать для этого where T:new()), и как вместо того, чтобы пытаться сопоставить string s, вы должны использовать настраиваемый бизнес-объект, Но, сделав некоторый пример кода, я довольно застрял. Я не могу придумать никакого сценария, который имеет смысл с помощью new string() == string.Empty.

Ответ 7

В частности, как избежать проблемы ограничения new() при работе с общими типами:

Включить следующее поле, свойство и метод:

private readonly Func<T> _defaultValueFactory = (Func<T>)DefaultT;
private Func<T> DefaultValueFactory
{
    get
    {
        return _defaultValueFactory;
    }
}

private static T DefaultT()
{
    return default(T);
}

Также включите конструктор для вашего типа, который принимает Func<T> defaultValueFactory.

Если вы обычно используете new T(), используйте DefaultValueFactory().

Ответ 8

От http://msdn.microsoft.com/en-gb/library/system.string.aspx

Объект A String называется неизменяемым (только для чтения), поскольку его значение     не может быть изменен после его создания. Появившиеся методы     для изменения объекта String фактически возвращает новый объект String    который содержит модификацию. Если необходимо изменить     фактическое содержимое строкоподобного объекта, используйте System.Text.StringBuilder    класс.

Таким образом, конструктор без параметров не имеет смысла.

Ответ 9

Все пустые строки одинаковы. Почему вы хотите его создать? Вы можете использовать String.Empty или просто "".

Ответ 10

Что будет

String s = new String();

предоставит вам

String s = String.Empty;

или

String s = null;

Ответ 11

Int32 - это структура. Структуры ВСЕГДА имеют конструктор без параметров. Это не имеет ничего общего с полезностью - даже если Microsoft решит, что конструктор Int32 без параметров полностью и совершенно бесполезен, они абсолютно ничего не могут с этим поделать. И если бы они хотели изменить поведение структур сейчас, это было бы огромным изменением. Превращение Int32 в класс также не представляется возможным, так как есть причина, по которой .net поддерживает тип Value и Reference (я слышал от ребята Java, что факт, что Integer является классом, вызывает некоторые проблемы, но я не могу комментировать на самом деле).

С другой стороны, String - это класс. Для классов вы можете контролировать, имеет или нет конструктор без параметров, поэтому здесь можно было увидеть, что это бесполезно и опустить его.