Система. Строка - почему это не реализует конструктора без параметров?

Я хотел спросить, что является идеей позади факта та Система. Строка не содержит конструктора без параметров.

Из-за этого Вы не можете использовать этот тип, когда там является новым () ограничение.

ОБНОВЛЕНИЕ

То, почему Вы думаете, что новая строка () является бесполезным и например, новым интервалом () не бесполезно. Я действительно не вижу различия. Я действительно хотел бы смочь использовать новое () ограничение на строку, начиная с того, что я ожидаю, Строка. Пустой.

UPDATE2

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

UPDATE3

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

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

UPDATE4

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

Заранее спасибо за справку.

26
задан empi 16 March 2010 в 19:41
поделиться

11 ответов

Если бы вы могли использовать

string s = new string();

, что бы вы с ним сделали? Строки неизменны.


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

Не забывайте, что ОП сказал, что он хотел сделать:

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

// Call:
SomeMethod<string>();

Я не понимаю, что вы могли бы сделать с t после того, как он был построен.

25
ответ дан 28 November 2019 в 07:18
поделиться

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

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

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

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

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

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

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

1
ответ дан 28 November 2019 в 07:18
поделиться

Что такое строка без реальной строки?

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

  String s = "hello world";

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

string s = string.empty
3
ответ дан 28 November 2019 в 07:18
поделиться

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

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

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

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

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

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

(Спасибо, Microsoft, я ценю вашу патерналистскую помощь, но я вполне способен позаботиться о себе. Если я не хочу создавать несколько экземпляров одного и того же объекта, я кэширую его, как и я сделайте для множества других типов с конструктором по умолчанию.)

На данный момент вам нужно рассматривать объекты без конструкторов по умолчанию как особый случай из всего остального. Перепишите

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

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

11
ответ дан 28 November 2019 в 07:18
поделиться

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

0
ответ дан 28 November 2019 в 07:18
поделиться

Что

String s = new String();

даст вам вместо

String s = String.Empty;

или

String s = null;
-1
ответ дан 28 November 2019 в 07:18
поделиться

Из http://msdn.microsoft.com/en-gb/library/system.string.aspx

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

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

0
ответ дан 28 November 2019 в 07:18
поделиться

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

Это невозможно сделать чисто на C #. Лучше всего использовать ограничение class , а затем использовать хакер на основе отражения для построения по умолчанию 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);
1
ответ дан 28 November 2019 в 07:18
поделиться

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

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

-1
ответ дан 28 November 2019 в 07:18
поделиться

Я предполагаю, что вы хотите определить класс, который выглядит примерно так:

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 следующим образом:

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

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

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

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

4
ответ дан 28 November 2019 в 07:18
поделиться

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

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

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

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

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

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

1
ответ дан 28 November 2019 в 07:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: