Подтвердить что ты не робот

С# зачем нужна структура, если класс может ее покрыть?

Просто интересно, зачем нам нужна структура, если класс может делать все struct can и больше? Полагаю, что значения типов значений в классе не имеют побочного эффекта.

EDIT: не вижу серьезных причин использовать struct

Структура похожа на класс со следующими ключевыми отличиями:

  • Структура - это тип значения, тогда как class является ссылочным типом.
  • Структура не поддерживает наследование (за исключением неявно вытекающих из объект).
  • Структура может иметь всех членов класс может, за исключением следующего:
  • Безпараметрический конструктор
  • Финализатор
  • Виртуальные участники

Вместо класса используется структура, когда желательна семантика типа значения. Хорошие примеры структур - это числовые типы, где для назначения более естественно копировать значение, а не ссылку. Поскольку struct является типом значения, каждый экземпляр не требует создания экземпляра объекта в куче. Это может быть важно при создании многих экземпляров типа.

4b9b3361

Ответ 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

В общем, используйте класс.

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

Ответ 7

Для среднего разработчика приложений использование классов является нормой. На первый взгляд, классы делают структуры кажущимися ненужными, но когда вы копаете глубже в мелочные детали, они на самом деле совершенно разные.

См. здесь для некоторых различий между структурами и классами.

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

Ответ 8

1, производительность. В некоторых случаях с использованием структур мы получим намного лучшую производительность.
2, неизменность данных. Изменяя какое-либо свойство структуры, вы получите новую структуру. Это очень полезно в некоторых случаях
3, лучший контроль в представлении памяти. Мы можем точно определить, как структура находится в памяти, и это позволяет быстро и эффективно сериализовать и десериализовать некоторые двоичные данные.

Ответ 9

Это почти необходимо использовать для взаимодействия с базовой структурой данных, используемой API win32. Полагаю, из-за этой причины очень большая причина иметь его в .net.