Почему CLR повторно использует пустые строки, а не пустые массивы? - PullRequest
14 голосов
/ 27 октября 2011

замечаю, что

Console.WriteLine((object) new string(' ', 0) == (object) new string(' ', 0));

печатает true, что указывает на то, что CLR хранит пустую строку и повторно использует тот же экземпляр. (Он печатает false для любого другого числа, кроме 0.)

Однако то же самое не верно для массивов:

Console.WriteLine(new int[0] == new int[0]);   // False

Теперь, если мы посмотрим на реализацию Enumerable.Empty<T>(), мы обнаружим, что она кэширует и повторно использует пустые массивы:

public static IEnumerable<TResult> Empty<TResult>()
{
    return EmptyEnumerable<TResult>.Instance;
}

[...]

public static IEnumerable<TElement> Instance
{
    get
    {
        if (EmptyEnumerable<TElement>.instance == null)
            EmptyEnumerable<TElement>.instance = new TElement[0];
        return EmptyEnumerable<TElement>.instance;
    }
}

Итак, команда разработчиков почувствовала, что хранение пустого массива для каждого типа того стоит. CLR может, если захочет, сделать небольшой шаг вперед и сделать это изначально, поэтому он применяется не только к вызовам на Enumerable.Empty<T>(), но также и new T[0]. Если оптимизация в Enumerable.Empty<T>() того стоит, то наверняка это будет еще дороже?

Почему CLR не делает этого? Я что-то упускаю?

Ответы [ 2 ]

9 голосов
/ 27 октября 2011

Строки могут использовать интернирование, что делает их другой историей (из всех других видов объектов).

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

static int[] empty = new int[0];
...
   lock (empty) { ... }

Если какой-то другой код заблокирован на другом (они думали) пустом int[], у вас может быть тупик, который очень трудно найти.

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

0 голосов
/ 12 декабря 2011

Создание объекта с помощью «new» всегда создаст новый экземпляр, который может быть заблокирован отдельно от любого другого экземпляра и о котором ReferenceEquals будет сообщать в отличие от всех других экземпляров. Если бы существовали системные фабричные методы или свойства для создания пустых массивов, аналогичные Enumerable .Empty или String.Empty, эти свойства могли бы возвращать экземпляры общего объекта, но открытые конструкторы не могут делать ничего, кроме возврата нового экземпляра или броска исключение.

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