Преимущество объекта класса в том, что можно передавать ссылку на него, при этом область действия и время жизни такой ссылки неограничены, если он достигает внешнего кода. Преимущество структуры состоит в том, что, хотя можно передавать недолговечные ссылки на них, , а не можно передавать бесконечные беспорядочные ссылки. Это помогает избежать беспокойства о том, существуют ли такие ссылки.
Некоторые люди считают, что носители данных, которые могут изменяться, не должны быть структурами. Я категорически не согласен. Сущности, которые существуют для хранения данных, во многих случаях должны быть структурами , особенно , если они изменчивы. Эрик Липперт много раз писал, что считает изменяемые типы значений злыми (ищите по тегам «изменяемый» и «структура»). Это, безусловно, правда, что .net позволяет выполнять определенные вещи с изменяемыми структурами, чего не следует делать, и не позволяет удобно делать некоторые вещи, которые он должен делать, но структуры POD ("Plain Old Data"), которые не имеют методов мутации, но вместо этого выставляйте все свое состояние через открытые поля, имейте очень полезную согласованность в своем поведении, которое не передается никаким другим типам данных Использование структуры POD может сбить с толку тех, кто не знаком с тем, как они работают, но сделает программу намного более читабельной для любого, кто это сделает.
Рассмотрим, например, следующий код, предполагая, что EmployeeInfoStruct не содержит ничего, кроме типов значений и неизменных типов классов, таких как String:
[employeeInfoStruct is a struct containing the following field]
public Decimal YearlyBonus;
[someEmployeeContainer is an instance of a class which includes the following method]
EmployeeInfoStruct GetEmployeeInfo(String id); // Just the signature--code is immaterial
[some other method uses the following code]
EmployeeInfoStruct anEmployee = someEmployeeContainer.GetEmployeeInfo("123-45-6789");
anEmployee.YearlyBonus += 100;
Эрик Липперт жалуется, что приведенный выше код изменит значение в anEmployee, но это изменение не повлияет на контейнер. Я хотел бы предположить, что это хорошо - любой, кто знает, как работает структура, может взглянуть на приведенный выше код и знает, что запись в переменную структуры повлияет на эту переменную, но не повлияет на что-либо еще, если в дальнейшем программа не использует какой-либо другой метод (возможно, SetEmployeeInfo) для хранения этой переменной где-либо.
Теперь замените EmployeeInfoStruct на EmployeeInfoClass, который имеет свойство чтения / записи типа YearlyBonus. Используя только приведенную выше информацию, что можно сказать об отношениях между записями в someEmployeeContainer и anEmployee? В зависимости от реализаций класса anEmployee (который, если EmployeeInfoClass не является закрытым, может или не может быть на самом деле EmployeeInfoClass) и someEmployeeContainer, отношения между объектами могут быть любыми. Пишет кому-то:
- не влияет на других
- Обновите другой «естественным» способом
- Повредить другого каким-то образом
С структурами, не содержащими ничего, кроме полей типов значений или неизменяемых классов, семантика всегда будет # 1. Чтобы узнать это, не нужно смотреть ни на код самой структуры, ни на код контейнера. Напротив, если anEmployee.Salary или someEmployeeContainer.GetEmployee являются виртуальными, невозможно реально знать, какой будет семантика.
Важно отметить, что, если структуры большие, передача их по значению или возврат из функций может быть дорогостоящим. Обычно лучше, когда это возможно, передавать большие структуры как ref
параметры. Несмотря на то, что встроенные коллекции действительно не способствуют такому использованию, они могут сделать использование структуры размером в сотни байтов дешевле, чем использование класса.