Почему C # использует структуры вместо классов для внутренних KeyValuePairs

1

Я находился под структурами показа, которые следует использовать для:

  • кратковременные значения (обычно выживают для жизни всего объекта)
  • размер до 16 байт (обычно это строковые ключи, которые могут легко превышать такие

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

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

Но даже тогда, возможно, быстрее вернуть только скопированный KeyValueNode, если это произойдет, нет?

Источник: http://referencesource.microsoft.com/#mscorlib/system/collections/generic/keyvaluepair.cs,8585965bb176a426

  • 4
    Утверждение «типы значений идут в стек» не является верным утверждением. Вы, кажется, думаете, что это так, учитывая ваш вопрос, но это совсем не так. Единственное различие между типом значения и ссылочным типом состоит в том, что всякий раз, когда вы используете экземпляр этого типа, тип значения является фактическим значением, а для ссылочного типа значение является просто ссылкой на то, где находится фактическое значение. Все остальное вытекает из этой основной предпосылки.
Теги:
class
struct
equality

3 ответа

2

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

Если Dictionary должен поддерживать массив ссылок на объекты с ключом-стоимостью, стоимость того, чтобы его перечислитель возвращал ссылки на элементы в этом массиве, был бы немного меньше, чем стоимость того, чтобы вернуть экземпляр элементов из массива, структуры пары ценностей. Кроме того, когда словарь расширяется, стоимость копирования ссылок на объекты с ключом будет немного меньше стоимости копирования структур пары "ключ-значение". Однако общая стоимость добавления предметов в словарь будет увеличена, так же как и стоимость извлечения значений (в отличие от пар ключ-значение). Для большинства распространенных случаев использования словаря использование объекта "ключ-значение-пара" окажется более дорогостоящим, чем использование структуры.

0

В дополнение к причинам, которые вы указали, еще одна важная причина, по которой вы можете использовать структуры, состоит в том, что две структуры с одинаковым значением считаются равными при использовании с методом Equals() если метод equals не переопределяется, поскольку они являются значениями типы, подобно двум переменным типа int будут равны, если они имеют одинаковое значение. Ссылаясь на документацию для KeyValuePair, вы можете видеть, что метод Equals наследуется от ValueType, который выполняет как таковой, когда сравниваются два значения. Это важно для пар ключ/значение из-за выполняемого ими задания, которое содержит значения с уникальными ключами в коллекции, а операции против этих пар используют метод Equals под капотом, когда вы проверяете, есть ли в нем ключ Коллекция.

Например, предположим, что у вас есть эта структура:

struct MyStruct
{
    public System.IO.Stream Value { get; set; }
}

Следующее выведет "True":

var input = System.IO.File.OpenRead(myPath);
var myFirstStruct = new MyStruct();
var mySecondStruct = new MyStruct();
myFirstStruct.Value = input;
mySecondStruct.Value = input;
System.Diagnostics.Debug.Print(myFirstStruct.Equals(mySecondStruct).ToString());

Но если у меня есть этот класс:

class MyClass
{
    public System.IO.Stream Value { get; set; }
}

Затем выводится "False":

var input = System.IO.File.OpenRead(myPath);
var myFirstClass = new MyClass();
var mySecondClass = new MyClass();
myFirstClass.Value = input;
mySecondClass.Value = input;
System.Diagnostics.Debug.Print(myFirstClass.Equals(mySecondClass).ToString());

Увидеть разницу? Во втором примере два экземпляра не равны, поскольку классы являются ссылочными типами, а не типами значений.

  • 0
    И структуры, и классы могут переопределять свои методы Equals . Они имеют разные реализации по умолчанию, но поскольку реализация всегда может быть переопределена, это никогда не является причиной для выбора одной над другой.
  • 0
    @Servy - Можете ли вы предложить, как я могу улучшить этот ответ? Или ты думаешь, что я совершенно не в курсе?
Показать ещё 6 комментариев
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню