Foreversoft.ru

IT Справочник
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Структуры в си шарп

Структуры

Как вам должно быть уже известно, классы относятся к ссылочным типам данных. Это означает, что объекты конкретного класса доступны по ссылке, в отличие от значений простых типов, доступных непосредственно. Но иногда прямой доступ к объектам как к значениям простых типов оказывается полезно иметь, например, ради повышения эффективности программы. Ведь каждый доступ к объектам (даже самым мелким) по ссылке связан с дополнительными издержками на расход вычислительных ресурсов и оперативной памяти.

Для разрешения подобных затруднений в C# предусмотрена структура, которая подобна классу, но относится к типу значения, а не к ссылочному типу данных. Т.е. структуры отличаются от классов тем, как они сохраняются в памяти и как к ним осуществляется доступ (классы — это ссылочные типы, размещаемые в куче, структуры — типы значений, размещаемые в стеке), а также некоторыми свойствами (например, структуры не поддерживают наследование). Из соображений производительности вы будете использовать структуры для небольших типов данных. Однако в отношении синтаксиса структуры очень похожи на классы.

Главное отличие состоит в том, что при их объявлении используется ключевое слово struct вместо class. Ниже приведена общая форма объявления структуры:

где имя обозначает конкретное имя структуры.

Как и у классов, у каждой структуры имеются свои члены: методы, поля, индексаторы, свойства, операторные методы и события. В структурах допускается также определять конструкторы, но не деструкторы. В то же время для структуры нельзя определить конструктор, используемый по умолчанию (т.е. конструктор без параметров). Дело в том, что конструктор, вызываемый по умолчанию, определяется для всех структур автоматически и не подлежит изменению. Такой конструктор инициализирует поля структуры значениями, задаваемыми по умолчанию. А поскольку структуры не поддерживают наследование, то их члены нельзя указывать как abstract, virtual или protected.

Объект структуры может быть создан с помощью оператора new таким же образом, как и объект класса, но в этом нет особой необходимости. Ведь когда используется оператор new, то вызывается конструктор, используемый по умолчанию. А когда этот оператор не используется, объект по-прежнему создается, хотя и не инициализируется. В этом случае инициализацию любых членов структуры придется выполнить вручную.

Давайте рассмотрим пример использования структур:

Обратите внимание, когда одна структура присваивается другой, создается копия ее объекта. В этом заключается одно из главных отличий структуры от класса. Когда ссылка на один класс присваивается ссылке на другой класс, в итоге ссылка в левой части оператора присваивания указывает на тот же самый объект, что и ссылка в правой его части. А когда переменная одной структуры присваивается переменной другой структуры, создается копия объекта структуры из правой части оператора присваивания.

Поэтому, если бы в предыдущем примере использовался класс UserInfo вместо структуры, получился бы следующий результат:

Назначение структур

В связи с изложенным выше возникает резонный вопрос: зачем в C# включена структура, если она обладает более скромными возможностями, чем класс? Ответ на этот вопрос заключается в повышении эффективности и производительности программ. Структуры относятся к типам значений, и поэтому ими можно оперировать непосредственно, а не по ссылке. Следовательно, для работы со структурой вообще не требуется переменная ссылочного типа, а это означает в ряде случаев существенную экономию оперативной памяти.

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

Любопытно, что в С++ также имеются структуры и используется ключевое слово struct. Но эти структуры отличаются от тех, что имеются в C#. Так, в С++ структура относится к типу класса, а значит, структура и класс в этом языке практически равноценны и отличаются друг от друга лишь доступом по умолчанию к их членам, которые оказываются закрытыми для класса и открытыми для структуры. А в C# структура относится к типу значения, тогда как класс — к ссылочному типу.

Структуры в языке C#

Вы уже знаете, что классы относятся к ссылочным типам данных. Это означает, что объекты конкретного класса доступны по ссылке. Ссылка -это 32/64-х битный адрес, указывающий на расположение членов-данных в управляемой куче, в отличие от значений простых типов, доступных непосредственно.

Читать еще:  Strcmp си описание

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

Для разрешения подобных затруднений в C# предусмотрена структура, которая подобна классу, но относится к типу значений, а не к ссылочному типу данных.

Структуры отличаются от классов тем, как они сохраняются в памяти и как к ним осуществляется доступ (для начала – краткая формула «классы — это ссылочные типы, размещаемые в куче, структуры — типы значений, размещаемые в стеке»). Эта формула не совсем точная, пояснения см. позже. Структуры отличаются от классов некоторыми свойствами (например, структуры не поддерживают наследование).

Из соображений производительности следует использовать структуры для небольших типов данных. Однако в отношении синтаксиса структуры очень похожи на классы.

Первое и очевидное отличие состоит в том, что при их объявлении используется ключевое слово struct вместо class. Ниже приведена общая форма объявления структуры:

struct имя
<
объявления членов
>
где имя обозначает конкретное имя структуры.

Как у класса, так и у каждой структуры имеются свои члены: методы, поля, индексаторы, свойства, операторные методы и события. Так в структуре Double (библиотека System) определено 6 констант, 6 операторов отношения, 19 методов, 5 интерфейсов (проверьте, используя интеллектуальную подсказку). Не многовато ли для вещественного числа, как вы думаете?

В структурах допускается также определять конструкторы. В то же время для структуры нельзя определить конструктор, используемый по умолчанию (без параметров), который определяется для всех структур автоматически и не подлежит изменению. Такой конструктор инициализирует поля структуры значениями, задаваемыми по умолчанию (false для типа bool, 0 – для чисел). А поскольку структуры в отличие от классов не поддерживают наследование, то их члены нельзя указывать как abstract, virtual или protected.

Экземпляр (можно говорить и «объект») структуры может быть создан с помощью оператора new таким же образом, как и объект класса, но в этом нет особой необходимости. Когда используется оператор new, то вызывается конструктор, используемый по умолчанию. А когда этот оператор не используется, объект по-прежнему создается, хотя и не инициализируется. В этом случае инициализацию любых членов структуры придется выполнить вручную. Рассмотрим пример.

Результат выполнения программы:


Исследуем программу. Закомментируем вторую строку в методе Main():
// stud1.name = «Петр»;
При запуске программы получим сообщение об ошибке:
Использование локальной переменной «stud1», которой не присвоено значение.
Хотя структура stud1 объявлена, но полю name никакого значения не присвоено, что приводит к ошибке. Такая же ошибка возникнет, если мы станем использовать переменную целого типа, которая объявлена, но не инициализирована.
Такой вот жесткий контроль компилятора за нашими действиями!

Проверим, как работает конструктор без параметров. Первую строку метода Main() заменим на
student stud1 = new student();
Вторую и третью строку – закомментируем. Тогда при выводе результата в 1 строке получим:
студент 1: Имя: , возраст: 0
Следовательно, полю name была присвоена пустая строка, а полю возраст – число 0.

Проверим, как работает защита данных. В второй строке описания структуры student удалим модификатор поля public, т.е. получим byte age;
При запуске программы получим два сообщения об ошибке:
«ConsoleApplication1.student.age» недоступен из-за его уровня защиты
в операторах stud1.age = 18; и stud2.age = 19;

Это означает, что так как по умолчанию поле age является полем private, то оно не может быть изменено в другом классе с помощью оператора присваивания, однако оно доступно методам класса student, объявленным как public. С учетом этих результатов, программа может быть записана так:

Здесь поля объектов stud1 и stud2 структуры student являются private-полями, а метод и конструктор объявлены как public.

А теперь ВНИМАНИЕ! Ключевая идея — Создание сложных конструкций данных, используя один тип данных, как элемент другой конструкции. В статье про типы данных мы выяснили, что все встроенные типы, относящиеся к типам значений (их еще называют простыми типами данных), являются структурами, хотя фактически каждая из них имеет одно поле, содержащее значение числа, символа или булевой переменной.

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

Читать еще:  Как зайти в безопасный режим samsung

Для понимания этой идеи рассмотрим пример. Прототипом для него являются структуры из библиотеки System. Drawing: Point, Size и Rectangle.

Известно, что точка на экране задается парой целых чисел (X,Y) в пикселях. Объединим эти два числа в структуру точка. Установим максимальную защиту (private – по умолчанию) для этих полей. Добавим конструктор с параметрами точка(x,y) для инициализации объектов структуры точка, а также метод Get() для извлечения полей в строковом формате.

Размер прямоугольника на экране также задается парой чисел: шириной и высотой. Соответственно объявим структуру размер с полями (W,H). Добавим аналогичный конструктор с параметрами размер(w,h) для инициализации объектов структуры размер, а также метод Get() для извлечения полей в строковом формате.

Прямоугольник на экране определяется координатами верхнего левого угла (точка) и размером изображения (размер). Поэтому третью структуру построим на основе первых двух, назовем ее Rect (сокращенно от «прямоугольник»), полями которой будут объекты первых двух структур: точка P и размер S. Эти поля также будут защищенными (private – по умолчанию). Добавим в эту структуру конструктор с параметрами public Rect(int x, int y, int w, int h) и три метода: Get() для извлечения информации о прямоугольнике, Get_P() и Get_S для извлечения координат и размеров по отдельности.

В методе Main( ) последовательно инициализируем объект Rect r и покажем работу методов всех этих трех структур.


Конечно, если бы поля всех структур были объявлены с модификатором public, то в принципе можно обходиться структурами, имеющими только поля без методов. Но помня о том, что структуры похожи на классы, следует и к ним применять те же общие принципы, что и для классов в части защиты данных.

BestProg

Использование массивов в структурах. Массивы структур. Вложенные структуры. Копирование структур

Содержание

1. Как объявить одномерный массив структур? Пример

Ниже приведен программный код, выполняющий следующие действия:

  • объявляется структура типа Point , описывающая координаты точки на плоскости. Структура содержит внутренние поля (переменные x , y ), один метод доступа к переменным, свойства записи в структуру и чтения данных из структуры;
  • объявляет массив MP из 10 экземпляров (объектов) структур типа Point ;
  • демонстрирует использование массива MP в некотором методе.

Объявление структуры типа Point :

Объявление массива MP и его использование в программном коде некоторого обработчика события (приложение типа Windows Forms ).

2. Как объявить двумерный массив структур? Пример

Ниже приведен пример объявления и использования двумерного массива типа Point (см. предшествующий пункт).

3. Пример копирования (присвоения) одной структуры другой

Пусть задано объявление структуры Date , определяющей дату в календаре.

В следующем коде продемонстрировано копирование одной структуры другой.

Как видно из примера, экземпляры структур размещаются в разных участках памяти.

4. Пример структуры, реализующей методы интерфейса

Как известно, в структурах можно реализовывать методы интерфейса. В примере ниже приведено использование интерфейсных методов в структурах.

Пусть дан интерфейс IPoint и структура типа Point , которые имеют такое же объявление

В интерфейсе описывается метод IsPointOnPoint() , который может быть реализован в структуре Point . Структура Point наследует интерфейс IPoint . Метод IsPointOnPoint() определяет, лежат ли точки одна на другой (имеют ли они одинаковые координаты x , y ).

Нижеследующий программный код демонстрирует использование структуры типа Point и вызов интерфейсного метода IsPointOnPoint() .

5. Какие особенности использования массивов в структурах? Пример использования массивов в структуре

Если в структуре объявлен массив, то для него обязательно должна выделяться память с помощью оператора new .

Пример. Пусть задана структура Cars , которая описывает парк автомобилей. В структуре объявляется несколько массивов, которые определяющих характеристики автомобилей.

В нижеследующем программном коде демонстрируется использование массивов в структуре

6. Пример использования вложенных структур в программах

В примере объявлены три структуры с именами Date , WorkerName , Worker . Структура Worker описывает информацию о работнике и содержит две вложенные структуры Date и WorkerName . Также структура Worker содержит массив чисел типа float .

Использование структуры Worker в другом программном коде

C#: классы, структуры, наследование

Классы и структуры в C# относятся к пользовательским типам (Custom types), т.е. типам, введенным разработчиком.

Классы

Класс — самый общий ссылочный тип. Простейшее объявление класса выглядит следующим образом:

Перед ключевым словом class могут присутствовать атрибуты (attributes) и модификаторы класса (class modifiers): public , internal , abstract , sealed , static , unsafe и partial . После названия класса могут указываться параметры обобщенного типа (generic type parameters), базовый класс (base class) и интерфейсы (interfaces). Внутри фигурных скобок могут располагаться члены класса (сlass members): методы (methods), свойства (properties), индексаторы (indexers), события (events), поля (fields), конструкторы (constructors), перегруженные операторы (overloaded operators), вложенные типы (nested types) и файналазер (finalizer).

Читать еще:  Визуал студио си шарп

Поля (Fields)

Поле — это переменная, являющаяся членом класса или структуры.

У поля может быть модификатор readonly , который предотвратит изменение поля после того как оно будет создано. Такому полю значение может быть присвоено только при объявлении или во внутреннем конструкторе типа.

Инициализировать поля не обязательно. Поля, которым не присвоено значение, принимают значение по умолчанию ( 0 , , null , false ). Инициализация полей запускается до выполнения конструктора, в том порядке, в котором следуют поля.

Для удобства поля одного типа можно объявлять в одной инструкции через запятую. При этом атрибуты и модификаторы так же распространяются на все поля в списке.

Методы (Methods)

Метод представляет собой действие, состоящие из ряда инструкций. При вызове метод может принимать входные данные в виде параметров и возвращать данные в точку вызова в виде возвращаемого типа. Метод может возвращать тип void , т.е. не возвращать в точку вызова никакого значения. Метод также может возвращать данные в точку вызова с помощью параметров ref и out .

Сигнатура метода должна быть уникальна в пределах типа. Сигнатура метода включает его имя и типы передаваемых параметров (но не имена параметров и не возвращаемый тип).

Тип может содержать перегруженные методы, т.е. методы с одинаковыми именами. При этом типы параметров у перегруженных методов должны отличаться.

Конструкторы

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

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

В вызываемый конструктор можно передавать выражения, однако в таком выражении не должна присутствовать ссылка на this (например, чтоб вызвать метод объекта), но допустимо вызывать статические методы.

Автоматический конструктор. В том случае (и только в том случае) если для класса не задан ни один конструктор компилятор C# автоматически генерирует публичный (public) конструктор без параметров.

Для структур конструктор без параметров является встроенным, поэтому определить свой собственный нельзя. Роль конструктора в структуре — присвоить всем полям значение по умолчанию.

Непубличный конструктор. Конструктор необязательно должен быть публичным (public). Самый распространенный пример, когда может понадобиться непубличный конструктор — необходимость контролировать создание экземпляров класса через вызов статического метода. Такой класс сначала проверяет наличие уже созданного объекта и если он уже создан — возвращает его, если нет — создает новый. Также такой метод может возвращать определенный подкласс исходя из входных аргументов.

Инициализаторы объекта

Чтобы упростить инициализацию объекта, все его доступные поля и свойства могут быть инициализированы с помощью инициализатора объекта сразу после создания объекта.

Ссылка this

Ссылка this указывает на сам экземпляр объекта.

Ссылка this также разрешает неоднозначность между локальными переменными или параметрами и полями объекта.

Ссылку this допустимо использовать только с нестатичными членами класса или структуры.

Свойства (Properties)

Внешне свойства ничем не отличаются от полей, но внутри самого класса они отличаются тем, что подобно методам содержат логику. Свойства определяются также как поля, но с добавлением блока get/set .

get и set — это средства доступа к свойствам (accessors). get выполняется при чтении свойства. Он должен возвращать значение того же типа, что и само свойство. set выполняется когда свойству присваивается значение. Оно имеет скрытый параметр value того же типа, что и само свойство.

Хотя доступ к полям и свойствам осуществляется одинаково, свойства в отличие от полей предоставляют полный контроль над процессом присвоения и получения значений (например, метод set может выбрасывать исключения и т.д.).

Если из средств доступа установлен только get , свойство будет доступно только для чтения (read-only), а если только set — только для записи (write-only). Обычно для свойства создается частное поле, в котором сохраняются данные, но это не обязательно: свойство может возвращать результаты расчета других данных.

Как уже отмечалось, самое распространенное назначение свойств — получение и присвоение значения частным полям того же типа что и свойство. Это можно сделать автоматически, используя объявление автоматических свойств (automatic property).

Ссылка на основную публикацию
Adblock
detector