Когда я должен использовать структуру вместо класса?
MSDN говорит, что вы должны использовать структуры, когда вам нужны легкие объекты. Существуют ли другие сценарии, когда структура предпочтительнее класса?
некоторые люди, возможно, забыли, что:
структуры может есть методы.
структуры не может быть унаследован.
Я понимаю технические различия между структурами и классами, у меня просто нет хорошего ощущения , когда to используйте структуру.
14 ответов:
MSDN имеет ответ: выбор между классами и структурами.
в принципе, эта страница дает вам контрольный список из 4 элементов и говорит, чтобы использовать класс, если ваш тип не соответствует всем критериям.
не определять структуру, если тип имеет все следующее характеристики:
- он логически представляет собой одно значение, аналогичное примитивным типам (целое число, двойной и так далее).
- он размер экземпляра меньше 16 байт.
- она неизменна.
- он не должен быть в штучной упаковке часто.
Я удивлен, что не прочитал ни одного из предыдущих ответов этого, который я считаю самым важным аспектом:
Я использую структуры, когда мне нужен тип без личности. Например, 3D точка:
public struct ThreeDimensionalPoint { public readonly int X, Y, Z; public ThreeDimensionalPoint(int x, int y, int z) { this.X = x; this.Y = y; this.Z = z; } public override string ToString() { return "(X=" + this.X + ", Y=" + this.Y + ", Z=" + this.Z + ")"; } public override int GetHashCode() { return (this.X + 2) ^ (this.Y + 2) ^ (this.Z + 2); } public override bool Equals(object obj) { if (!(obj is ThreeDimensionalPoint)) return false; ThreeDimensionalPoint other = (ThreeDimensionalPoint)obj; return this == other; } public static bool operator ==(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2) { return p1.X == p2.X && p1.Y == p2.Y && p1.Z == p2.Z; } public static bool operator !=(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2) { return !(p1 == p2); } }если у вас есть два экземпляра этой структуры, вам все равно, являются ли они одним фрагментом данных в памяти или двумя. Вы просто заботитесь о ценности(ах), которые они держат.
Билл Вагнер имеет главу об этом в своей книге " Эффективный c# "(http://www.amazon.com/Effective-Specific-Ways-Improve-Your/dp/0321245660). он заключает, используя следующий принцип:
- является ли основная ответственность хранения данных типа?
- определяется ли его открытый интерфейс полностью свойствами, которые обращаются или изменяют его элементы данных?
- вы уверены, что ваш вид никогда не будет иметь подклассы?
- вы уверены, что ваш тип никогда не будет рассматриваться полиморфно?
Если вы ответите " да " на все 4 вопроса: использовать структуру struct. В противном случае используйте класс.
используйте структуру, когда вам нужна семантика типа значения вместо ссылочного типа. Структуры копируются по значению, поэтому будьте осторожны!
Также см. предыдущие вопросы, например,
Я бы использовал структуры, когда:
объект должен быть только для чтения(каждый раз, когда вы проходите/назначить структуру, он копируется). Объекты только для чтения отлично подходят для многопоточной обработки, поскольку в большинстве случаев они не требуют блокировки.
объект мал и недолговечен. В таком случае есть хороший шанс, что объект будет выделен в стеке, что намного эффективнее, чем поместить его в управляемую кучу. Более того, память, выделенная объектом, будет освобождена, как только она выйдет за его пределы. Другими словами это меньше работы для сборщика мусора и память используется более эффективно.
использовать класс, если:
- его идентичность важна. Структуры копируются неявно при передаче по значению в метод.
- он будет иметь большой объем памяти.
- его поля нуждаются в инициализаторах.
- вы должны наследовать от базового класса.
- вам нужно полиморфное поведение;
использовать структуру если:
- он будет действовать как примитивный тип (int, long, byte и т. д.).
- он должен иметь небольшой объем памяти.
- вы вызываете метод P / Invoke, который требует, чтобы структура была передана значение.
- нужно уменьшить влияние сборки мусора на производительность приложения.
- его поля должны быть инициализированы только их значения по умолчанию. Это значение будет равно нулю для числовых типов, false для Логические типы и null для ссылочных типов.
- обратите внимание, что в C# 6.0 структуры могут иметь конструктор по умолчанию, который может быть использован для инициализации поля структуры для значений по умолчанию.
- вам не нужно наследовать от базового класса (кроме ValueType, от которого все структуры наследуются).
- вам не нужно полиморфное поведение.
Я всегда использовал структуру, когда хотел сгруппировать несколько значений для передачи вещей из вызова метода, но мне не нужно будет использовать ее для чего-либо после того, как я прочитал эти значения. Просто как способ держать вещи в чистоте. Я склонен рассматривать вещи в структуре как "выброшенные", а вещи в классе как более полезные и"функциональные"
Если объект будет неизменяемым, вопрос о том, использовать ли структуру или класс, как правило, будет связан с производительностью, а не с семантикой. В 32/64-разрядной системе для хранения ссылок на классы требуется 4/8 байта, независимо от объема информации в классе; копирование ссылки на класс потребует копирования 4/8 байта. С другой стороны, каждый distinct экземпляр класса будет иметь 8/16 байт накладных расходов в дополнение к информации, которую он хранит и память стоимость ссылок на него. Предположим, что требуется массив из 500 объектов, каждый из которых содержит четыре 32-разрядных целых числа. Если объект является типом структуры, массив потребует 8000 байт независимо от того, все ли 500 объектов идентичны, все разные или где-то между ними. Если сущность является типом класса, массив из 500 ссылок займет 4000 байт. Если все эти ссылки указывают на разные объекты, для каждого объекта потребуется дополнительно 24 байта (12 000 байт для всех 500), a всего 16 000 байт-в два раза больше стоимости хранения типа структуры. С другой стороны, код создал один экземпляр объекта, а затем скопировал ссылку на все 500 слотов массива, общая стоимость будет составлять 24 байта для этого экземпляра и 4000 для массива-в общей сложности 4024 байта. Большая экономия. Немногие ситуации будут работать так же хорошо, как и последняя, но в некоторых случаях может быть возможно скопировать некоторые ссылки на достаточное количество слотов массива, чтобы сделать такой обмен полезным.
если сущность предполагается, что он изменчив, вопрос о том, использовать ли класс или структуру, в некотором смысле проще. Предположим, что "Вещь" является либо структурой, либо классом, который имеет целочисленное поле с именем x, и один делает следующий код:
Thing t1,t2; ... t2 = t1; t2.x = 5;нужно ли, чтобы последнее утверждение влияло на t1.x?
Если вещь является типом класса, t1 и t2 будут эквивалентны, что означает t1.x и t2.x также будет эквивалентен. Таким образом, второе утверждение будет влиять на t1.x. Если вещь является типом структуры, t1 и t2 будут разные экземпляры, то есть t1.x и t2.x будет относиться к различным целым числам. Таким образом, второе утверждение не повлияет на t1.x.
изменяемые структуры и изменяемые классы имеют принципиально разное поведение, хотя .net имеет некоторые причуды в обработке мутаций структуры. Если требуется поведение типа значения (это означает, что "t2=t1" будет копировать данные из t1 в t2, оставляя t1 и t2 как отдельные экземпляры), и если можно жить с причудами в обработке значения .net типы, структура. Если вы хотите семантику типа значения, но причуды .net приведут к нарушению семантики типа значения в своем приложении, используйте класс и mumble.
кроме того, отличные ответы выше:
структуры-это типы значений.
Они никогда не могут быть установлены в ничего.
установка структуры = ничего, установит все свои типы значений к их значениям по умолчанию.
когда вам не нужно поведение, но вам нужно больше структуры, чем простой массив или словарь.
последующие Вот как я думаю о структурах в целом. Я знаю, что у них могут быть методы, но мне нравится сохранять это общее умственное различие.
Как сказал @Simon, структуры предоставляют семантику "типа значения", поэтому, если вам нужно подобное поведение для встроенного типа данных, используйте структуру. Поскольку структуры передаются копией, вы хотите убедиться, что они небольшие по размеру, около 16 байт.
Мда...
Я бы не использовал сборку мусора в качестве аргумента за/против использования структур против классов. Управляемая куча работает так же, как стек - создание объекта просто помещает его в верхнюю часть кучи, что почти так же быстро, как выделение в стеке. Кроме того, если объект недолговечен и не переживает цикл GC, освобождение является бесплатным, поскольку GC работает только с памятью, которая все еще доступна. (Поиск в MSDN, там есть серия статей на .Чистую память управление, мне просто лень идти копать за ними).
большую часть времени я использую структуру, я заканчиваю тем, что пинаю себя за это, потому что позже я обнаруживаю, что наличие ссылочной семантики сделало бы вещи немного проще.
в любом случае, эти четыре пункта в статье MSDN, опубликованной выше, кажется хорошим руководством.
структуры находятся в стеке, а не в куче, поэтому они потокобезопасны и должны использоваться при реализации шаблона объекта передачи, вы никогда не хотите использовать объекты в куче, они изменчивы, вы хотите в этом случае использовать стек вызовов, это базовый случай для использования структуры я удивлен всеми ответами здесь,
Я думаю, что лучший ответ-просто использовать struct, когда вам нужна коллекция свойств, класс, когда это коллекция свойств и поведения.
Comments