С# зачем нужна структура, если класс может ее покрыть?
Просто интересно, зачем нам нужна структура, если класс может делать все struct can и больше? Полагаю, что значения типов значений в классе не имеют побочного эффекта.
EDIT: не вижу серьезных причин использовать struct
Структура похожа на класс со следующими ключевыми отличиями:
- Структура - это тип значения, тогда как
class является ссылочным типом.
- Структура не поддерживает наследование
(за исключением неявно вытекающих из
объект).
- Структура может иметь всех членов
класс может, за исключением следующего:
- Безпараметрический конструктор
- Финализатор
- Виртуальные участники
Вместо класса используется структура, когда желательна семантика типа значения. Хорошие примеры структур - это числовые типы, где для назначения более естественно копировать значение, а не ссылку. Поскольку struct является типом значения, каждый экземпляр не требует создания экземпляра объекта в куче. Это может быть важно при создании многих экземпляров типа.
Ответы
Ответ 1
Пользовательские типы значений не являются абсолютно необходимыми - например, Java без них. Тем не менее, они все еще могут быть полезны.
Например, в Noda Time мы используем их довольно широко, как эффективный способ представления таких вещей, как мгновенные события без накладных расходов объекта.
Я бы не сказал, что "класс может делать все struct can и больше" - они ведут себя по-разному и должны мыслиться по-разному.
Ответ 2
Зачем использовать struct
, когда работает class
? Потому что иногда class
не работает.
В дополнение к причинам производительности, упомянутым Ридом Копси (короткая версия: меньше объектов, которые GC должен отслеживать, что позволяет GC выполнять лучшую работу), есть одно место, где должны использоваться структуры: P/Invoke to функции, требующие структуры по значению или элементы структуры.
Например, предположим, что вы хотите вызвать функцию CreateProcess(). Предположим, что вы хотели использовать структуру STARTUPINFOEX для параметра lpStartupInfo для CreateProcess()
.
Хорошо, что STARTUPINFOEX
? Это:
typedef struct _STARTUPINFOEX {
STARTUPINFO StartupInfo;
PPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
} STARTUPINFOEX, *LPSTARTUPINFOEX;
Обратите внимание, что STARTUPINFOEX
содержит STARTUPINFO в качестве своего первого члена. STARTUPINFO
является структурой.
Поскольку классы являются ссылочными типами, если мы объявили соответствующий тип С# таким образом:
[StructLayout(LayoutKind.Sequential)]
class STARTUPINFO { /* ... */ }
class STARTUPINFOEX { public STARTUPINFO StartupInfo; /* ... */ }
Соответствующий макет памяти будет неправильным, так как STARTUPINFOEX.StartupInfo
будет указателем (4 байта на платформах ILP32), а не структурой (как требуется, размером 68 байт на платформах ILP32).
Итак, чтобы поддерживать вызовы произвольных функций, которые принимают произвольные структуры (что и есть P/Invoke), необходимо одно из двух:
-
Полностью поддерживайте типы значений. Это позволяет С# объявлять тип значения для STARTUPINFO
, который будет иметь правильный макет памяти для маршалинга (т.е. struct
поддержка, как у С#).
-
Некоторый альтернативный синтаксис внутри структур P/Invokeable, которые будут информировать маршалера времени выполнения о том, что этот элемент должен быть выложен как тип значения, а не как указатель.
(2) является работоспособным решением (и, возможно, оно использовалось в J/Direct в Visual J ++, я не помню), но учитывая, что правильные типы значений более гибкие, включите ряд оптимизаций производительности, которые иначе не достижимы, и сделать разумное использование в сценариях P/Invoke, неудивительно, что С# поддерживает типы значений.
Ответ 3
Структуры также часто требуются по соображениям производительности. Массивы структур занимают немного меньше памяти и намного лучше когерентность кэша, чем массив ссылок на объекты. Это очень важно, если вы работаете с чем-то вроде системы рендеринга и, например, должны генерировать 5 миллионов вершин.
Подробнее см. Рико Мариани Прогрессивная Опрос + Ответы.
Ответ 4
Структуры полезны просто потому, что они передаются по значению, что может быть полезно в некоторых алгоритмах. Это на самом деле то, что классы НЕ МОГУТ делать.
struct ArrayPointer<T>
{
public T[] Array;
public int Offset;
}
Вы можете передать эту структуру методу, и метод может изменить значение Offset для собственных нужд. Между тем, как только вы вернетесь из метода, он будет вести себя так, как если бы смещение никогда не менялось.
Ответ 5
В общем, используйте класс.
Используйте только структуру, когда вам абсолютно нужна семантика типа значения.
Ответ 6
Ответ 7
Для среднего разработчика приложений использование классов является нормой. На первый взгляд, классы делают структуры кажущимися ненужными, но когда вы копаете глубже в мелочные детали, они на самом деле совершенно разные.
См. здесь для некоторых различий между структурами и классами.
Наиболее известным отличием является то, что классы являются ссылочными типами, а структуры - это типы значений. Это важно, потому что это позволяет разработчику библиотеки контролировать, как можно использовать экземпляры типа данных.
Ответ 8
1, производительность. В некоторых случаях с использованием структур мы получим намного лучшую производительность.
2, неизменность данных. Изменяя какое-либо свойство структуры, вы получите новую структуру. Это очень полезно в некоторых случаях
3, лучший контроль в представлении памяти. Мы можем точно определить, как структура находится в памяти, и это позволяет быстро и эффективно сериализовать и десериализовать некоторые двоичные данные.
Ответ 9
Это почти необходимо использовать для взаимодействия с базовой структурой данных, используемой API win32. Полагаю, из-за этой причины очень большая причина иметь его в .net.