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

Strange Queue <T>.Enqueue(T item) код

Во время отражения с помощью ILSpy я нашел эту строку кода в Queue<T>.Enqueue(T item) -методе:

if (this._size == this._array.Length)
{
    int num = (int)((long)this._array.Length * 200L / 100L);
    if (num < this._array.Length + 4)
    {
        num = this._array.Length + 4;
    }
    this.SetCapacity(num);
}

Мне просто интересно, почему кто-то это сделает? Я думаю, что это какая-то целая проверка переполнения, но зачем сначала умножать на 200L, а затем делить на 100L?

Возможно, это была проблема с более ранними компиляторами?

4b9b3361

Ответ 1

Обычно вещи, которые сначала умножаются, а затем делятся на 100, представляют собой процентные вычисления. Возможно, в исходном коде было несколько const XxxPercentage = 200 или что-то в этом роде. Компилятор, похоже, не оптимизирует * 200 / 100 до * 2.

Этот код устанавливает емкость в два раза больше его размера, но если в два раза его размер будет меньше исходного размера + 4, используйте это вместо.

Причина, по которой он конвертируется в long, вероятно, состоит в том, что если вы умножаете целое число на 200 процентов, оно будет переполняться.

Ответ 2

Ниже приведены все то же самое и будет генерировать тот же результат:

int size = (int)((length * 200L) / 100L);
int size = length << 1;
int size = length * 2;

Причина выбора первого варианта над другим заключается в том, чтобы четко показать ваше намерение:

const long TotalArraySize = 200L;
const long BytesPerElement = 100L;
return (length * TotalArraySize) / BytesPerElement;

Ниже приведены некоторые сведения о последствиях производительности: Удвоение числа - сдвиг влево и умножение

Ответ 3

Если вы продолжаете искать реализацию Queue, вы найдете следующие поля:

const int _GrowFactor = 200;
const int _MinimumGrow = 4;

Интересно, что эти константы не используются:) Я думаю, что эти константы были жестко запрограммированы (фактор роста также заменен длинным типом). Давайте посмотрим на метод Enqueue с этой точки зрения:

if (this._size == this._array.Length)
{
    int capacity = (int)((this._array.Length * _GrowFactor) / 100L);
    if (capacity < (this._array.Length + _MinimumGrow))
    {
        capacity = this._array.Length + _MinimumGrow;
    }
    this.SetCapacity(capacity);
}

Я думаю, что эти имена имеют смысл. GrowFactor указывает в процентах, сколько массива должно расти. По умолчанию это 200%. Но они также указали минимальный рост для внутреннего массива. Таким образом, если массив не увеличился настолько, насколько текущая длина + минимум растет, мы дадим это минимальное увеличение в любом случае.

Ответ 4

Намерение * 200L / 100L не яснее, чем * 2, на мой взгляд. Единственная причина, по которой я могу думать о том, почему это делается, заключается в том, чтобы убедиться, что длина очереди может вырасти до 200 раз. Существует разница в * 200 / 100 и * 2, так что первая приведет к исключению переполнения для 100-кратного меньшего числа. Например, если это было для значений байта, x * 200 / 100 завершится с ошибкой для x == 2, но * 2 завершится с ошибкой, только если x будет размером 128.

Но как заметил Марсело Кантос, (long)this._array.Length * 200L / 100L никогда не переполнится, поэтому мой ответ, вероятно, мало помогает.

Может ли это быть "функцией" ILSpy? Возможно, в исходном коде это просто * 2.

ИЗМЕНИТЬ

После дополнительного исследования выясняется, что этот странный код должен быть артефактом некоторого рефакторинга. Я проверил, как это делается в List < >

private void EnsureCapacity(int min)
{
    if (this._items.Length < min)
    {
        int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
        if (num < min)
        {
            num = min;
        }
        this.Capacity = num;
    }
}

Это так же просто, как и следовало ожидать. Я предполагаю, что код Queue.Enqueue был переработан, но не полностью очищен, и из этого изменения появился какой-то странный код. Большинство разработчиков считают, что библиотеки Microsoft идеальны, и все имеет смысл, но вполне вероятно, что не каждая строка кода написана гением: -)