Когда использовать значения и ссылочные типы для неизменяемых типов? (.СЕТЬ) - PullRequest
8 голосов
/ 12 мая 2011

С изменяемыми типами разница в поведении между типами значений и ссылками очевидна:

// Mutable value type
PointMutStruct pms1 = new PointMutStruct(1, 2);
PointMutStruct pms2 = pms1;
// pms1 == (1, 2); pms2 == (1, 2);
pms2.X = 3;
MutateState(pms1); // Changes the X property to 4.
// pms1 == (1, 2); pms2 == (3, 2);

// Mutable reference type
PointMutClass pmc1 = new PointMutClass(1, 2);
PointMutClass pmc2 = pmc1;
// pmc1 == (1, 2); pmc2 == (1, 2);
pmc2.X = 3;
MutateState(pmc1); // Changes the X property to 4.
// pmc1 == (4, 2); pmc2 == (4, 2);

Однако с неизменяемыми типами эта разница менее заметна:

// Immutable value type
PointImmStruct pis1 = new PointImmStruct(1, 2);
PointImmStruct pis2 = pis1;
// pis1 == (1, 2); pis2 == (1, 2);
pis2 = new PointImmStruct(3, pis2.Y);
// Can't mutate pis1
// pis1 == (1, 2); pis2 == (3, 2);

// Immutable reference type
PointImmClass pic1 = new PointImmClass(1, 2);
PointImmClass pic2 = pic1;
// pic1 == (1, 2); pic2 == (1, 2);
pic2 = new PointImmClass(3, pic2.Y);
// Can't mutate pic1 either
// pic1 == (1, 2); pic2 == (3, 2);

Неизменяемые ссылочные типы также часто используют семантику значений (например, канонический пример System.String):

string s1 = GenerateTestString(); // Generate identical non-interned strings
string s2 = GenerateTestString(); // by dynamically creating them
// object.ReferenceEquals(strA, strB)) == false;
// strA.Equals(strB) == true
// strA == strB

Эрик Липперт ранее обсуждал в своем блоге (например, здесь ), что тот факт, что типы значений часто (когда это не имеет значения для этого обсуждения) выделяется в стеке, является деталью реализации, и что обычно это не должно указывать, делаете ли вы объект значением или ссылочным типом.

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

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

Ответы [ 3 ]

6 голосов
/ 12 мая 2011

Я бы сказал, что сообщение в блоге Эрика, на которое вы ссылаетесь, дает именно такой ответ:

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

Если ваши объекты должны иметь семантику «копировать по значению», то сделайте их типами значений.Если они должны иметь семантику «копия по ссылке», сделайте их ссылочными типами.

Он также говорит это, с чем я согласен:

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

2 голосов
/ 12 мая 2011

Существует важная категория неизменяемых типов (о которой Эрик Липперт также довольно подробно писал), которые должны быть реализованы как типы почитания: рекурсивные типы, такие как узлы списка, узлы дерева и тому подобное.Типы значений не могут иметь циклических определений, как, например, узел связанного списка:

class IntNode
{
    private readonly int value;
    private readonly IntNode next;
}
1 голос
/ 12 мая 2011

.NET намекает на ответ на этот вопрос с помощью класса String. Он неизменен, но является ссылочным типом. Сделайте ваш неизменный тип act максимально похожим на тип значения. Не имеет значения, является ли это типом значения.

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

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