Когда я должен использовать структуру вместо класса? - PullRequest
289 голосов
/ 17 сентября 2008

MSDN говорит, что вы должны использовать структуры, когда вам нужны легкие объекты. Существуют ли другие сценарии, когда структура предпочтительнее, чем класс?

Некоторые люди могли забыть, что:

  1. структуры могут иметь методы.
  2. структуры не могут быть унаследованы.

Я понимаю технические различия между структурами и классами, я просто не чувствую, что когда использует структуру.

Ответы [ 14 ]

289 голосов
/ 17 сентября 2008

MSDN имеет ответ: Выбор между классами и структурами .

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

Не определять структуру, если Тип имеет все следующие Характеристики:

  • Логически представляет одно значение, подобное примитивным типам. (целое, двойное и т. д.).
  • Размер экземпляра меньше 16 байт.
  • Он неизменен.
  • Это не должно быть часто в штучной упаковке.
53 голосов
/ 22 января 2009

Я удивлен, что не читал ни в одном из предыдущих ответов на этот вопрос, который я считаю наиболее важным аспектом:

Я использую структуры, когда хочу тип без идентификатора. Например, 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);
    }
}

Если у вас есть два экземпляра этой структуры, вам все равно, являются ли они одним фрагментом данных в памяти или двумя. Вы просто заботитесь о ценности, которую они имеют.

27 голосов
/ 14 июня 2011

У Билла Вагнера есть глава об этом в его книге «Эффективный с #» (http://www.amazon.com/Effective-Specific-Ways-Improve-Your/dp/0321245660).. В заключение он использует следующий принцип:

  1. Является ли основная ответственность за тип хранения данных?
  2. Определяется ли его открытый интерфейс полностью свойствами, которые обращаются к его элементам данных или изменяют их?
  3. Вы уверены, что у вашего типа никогда не будет подклассов?
  4. Вы уверены, что ваш тип никогда не будет рассматриваться полиморфно?

Если вы ответите «да» на все 4 вопроса: используйте структуру. В противном случае используйте класс.

15 голосов
/ 17 сентября 2008

Используйте структуру, когда вы хотите семантику типа значения вместо ссылочного типа. Структуры копируются по значению, поэтому будьте осторожны!

Также смотрите предыдущие вопросы, например,

В чем разница между struct и class в .NET?

11 голосов
/ 17 сентября 2008

Я бы использовал структуры, когда:

  1. объект должен быть только для чтения (каждый раз, когда вы передаете / назначаете структуру, он копируется). Объекты только для чтения отлично подходят для многопоточной обработки, поскольку в большинстве случаев они не требуют блокировки.

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

9 голосов
/ 16 декабря 2015

Используйте класс, если:

  • Его личность важна. Структуры неявно копируются при передаче по значению в метод.
  • У него будет большой объем памяти.
  • Его поля нуждаются в инициализаторах.
  • Вам нужно наследовать от базового класса.
  • Вам нужно полиморфное поведение;

Используйте структуру, если:

  • Он будет действовать как примитивный тип (int, long, byte и т. Д.).
  • Он должен иметь небольшой объем памяти.
  • Вы вызываете метод P / Invoke, который требует, чтобы структура передавалась значение.
  • Вам необходимо уменьшить влияние сборки мусора на производительность приложений.
  • Его поля должны быть инициализированы только с их значениями по умолчанию. Это значение будет нулевым для числовых типов, ложным для логических типов и нулевым для ссылочных типов.
    • Обратите внимание, что в C # 6.0 структуры могут иметь конструктор по умолчанию, который можно использовать для инициализации поля структуры для значений по умолчанию.
  • Вам не нужно наследовать от базового класса (кроме ValueType, из которого все структуры наследуют).
  • Вам не нужно полиморфное поведение.
5 голосов
/ 17 сентября 2008

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

4 голосов
/ 18 ноября 2011

Если сущность будет неизменной, вопрос о том, использовать ли структуру или класс, обычно будет касаться производительности, а не семантики. В 32/64-битной системе для ссылок на классы требуется 4/8 байт для хранения, независимо от объема информации в классе; копирование ссылки на класс потребует копирования 4/8 байтов. С другой стороны, каждый отдельный экземпляр класса будет иметь 8/16 байтов служебной информации в дополнение к информации, которую он содержит, и стоимости памяти ссылок на него. Предположим, кто-то хочет массив из 500 объектов, каждый из которых содержит четыре 32-разрядных целых числа Если объект является структурным типом, массиву потребуется 8000 байтов независимо от того, все ли 500 объектов идентичны, различны или где-то между ними. Если сущность является типом класса, массив из 500 ссылок займет 4000 байтов. Если все эти ссылки указывают на разные объекты, для этих объектов потребуются дополнительные 24 байта каждый (12 000 байтов для всех 500), всего 16 000 байтов - вдвое больше, чем стоимость хранения типа структуры. С другой стороны, из кода, который создал один экземпляр объекта, а затем скопировал ссылку на все 500 слотов массива, общая стоимость составила бы 24 байта для этого экземпляра и 4000 для массива - всего 4024 байта. Основная экономия. Немногие ситуации сработают так же хорошо, как и последняя, ​​но в некоторых случаях возможно скопировать некоторые ссылки на достаточное количество слотов массива, чтобы сделать такое совместное использование полезным.

Если объект должен быть изменчивым, вопрос о том, использовать ли класс или структуру, в некотором смысле проще. Предположим, что «Thing» - это либо структура, либо класс, у которого есть целочисленное поле с именем x, и каждый выполняет следующий код:

  Thing t1,t2;
  ...
  t2 = t1;
  t2.x = 5;

Желает ли последнее утверждение повлиять на t1.x?

Если Thing является типом класса, t1 и t2 будут эквивалентны, то есть t1.x и t2.x также будут эквивалентны. Таким образом, второе утверждение повлияет на t1.x. Если Thing является структурным типом, t1 и t2 будут разными экземплярами, то есть t1.x и t2.x будут ссылаться на разные целые числа. Таким образом, второе утверждение не повлияет на t1.x.

Изменчивые структуры и изменяемые классы имеют принципиально различное поведение, хотя .net имеет некоторые особенности в обработке структурных мутаций. Если кто-то хочет поведение типа значения (имеется в виду, что «t2 = t1» будет копировать данные из t1 в t2, оставляя t1 и t2 как отдельные экземпляры), и если кто-то может согласиться с особенностями обработки значений в .net, используйте структура. Если кто-то хочет семантику типа значения, но причуды .net могут привести к нарушению семантики типа значения в приложении, используйте класс и бормотайте.

3 голосов
/ 28 августа 2013

Кроме того, превосходные ответы выше:

Структуры являются типами значений.

Они никогда не могут быть установлены на Ничего .

Установка структуры = Ничего, установит для всех типов значений значения по умолчанию.

2 голосов
/ 17 сентября 2008

Как сказал @Simon, структуры предоставляют семантику типа значения, поэтому, если вам нужно поведение, подобное встроенному типу данных, используйте структуру. Поскольку структуры передаются при копировании, необходимо убедиться, что они имеют небольшой размер, около 16 байт.

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