- Обзор классов, структур и записей в C #
- Инкапсуляция
- Участники
- Специальные возможности
- Наследование
- Интерфейсы
- Универсальные типы
- Статические типы
- Вложенные типы
- Разделяемые типы
- Инициализаторы объектов
- Анонимные типы
- Методы расширения
- Неявно типизированные локальные переменные
- Записи
- Спецификация языка C#
- Си шарп структура это
- Определение структуры
- Создание объекта структуры
- Инициализация с помощью конструктора
- Непосредственная иницилизация полей
- Инициализация полей по умолчанию
- Конструкторы структуры
- Инициализатор структуры
- Копирование структуры с помощью with
Обзор классов, структур и записей в C #
В C# определение типа ( класса, структуры или записи) похоже на схему, которая определяет, что может сделать тип. В сущности, объект является блоком памяти, выделенной и настроенной в соответствии с чертежом. В этой статье приводятся общие сведения об этих схемах и их возможностях. В следующей статье этой серии представлены объекты.
Инкапсуляция
Концепцию инкапсуляции признают одним из основополагающих принципов объектно-ориентированного программирования. В классе или структуре можно указать уровень доступности для обращения к каждому из его членов из кода, расположенного вне этого класса или структуры. Вы можете скрыть методы и переменные, которые не предназначены для использования вне класса или сборки. Это позволяет снизить риск ошибок в коде и вредоносных действий. Дополнительные сведения см. в руководстве по объектно-ориентированному программированию .
Участники
Члены типа включают все методы, поля, константы, свойства и события. В C# не существует глобальных переменных или методов, как в некоторых других языках. Даже точка входа программы, то есть метод Main , должна быть объявлена внутри класса или структуры (для инструкций верхнего уровня — неявным образом).
Ниже приведен полный список возможных элементов, которые можно объявить в классе, структуре или записи.
- Поля
- Константы
- Свойства
- Методы
- Конструкторы
- События
- Методы завершения
- Индексаторы
- Операторы
- Вложенные типы
Дополнительные сведения см. в разделе «Участники».
Специальные возможности
Некоторые методы и свойства специально предназначены для того, чтобы их вызов или доступ к ним осуществлялся из клиентского кода, то есть из кода за пределами этого класса или структуры. Другие методы и свойства могут использоваться только в самом классе или структуре. Важно ограничить доступность кода так, чтобы только нужные элементы клиентского кода получали к нему доступ. Уровень доступности для типов и их элементов вы можете задать с помощью следующих модификаторов доступа.
По умолчанию используется режим доступа private .
Наследование
Классы (но не структуры) поддерживают наследование. Класс, производный от другого класса, называемого базовым классом, автоматически включает все открытые, защищенные и внутренние члены базового класса за исключением конструкторов и методов завершения.
Классы могут быть объявлены как абстрактные. Это означает, что один или несколько их членов не имеют реализации. Из абстрактных классов нельзя напрямую создать экземпляры. Они выполняют роль базовых классов для других классов, которые предоставляют реализацию недостающих членов. Также классы можно объявить запечатанными, чтобы запретить наследование от них других классов.
Дополнительные сведения см. в статьях о наследовании и полиморфизме.
Интерфейсы
Классы, структуры и записи могут реализовывать несколько интерфейсов. Реализация из интерфейса означает, что тип реализует все методы, определенные в интерфейсе. Дополнительные сведения см. в статье Интерфейсы.
Универсальные типы
Для класса, структуры или записи можно определить один параметр типа или несколько. Клиентский код назначает тип при создании экземпляра типа. Например, класс List в пространстве имен System.Collections.Generic определен с помощью одного параметра типа. Клиентский код создает экземпляр List или List , информируя о том, сущности какого типа будут храниться в этом списке. Дополнительные сведения см. в статье Универсальные шаблоны.
Статические типы
Классы (но не структуры или записи) могут быть объявлены как static . Статический класс может содержать только статические элементы. Для него нельзя создать экземпляр с помощью ключевого слова new . При запуске программы в память загружается одна копия такого класса. Доступ к его членам осуществляется через имя класса. Классы, структуры и записи могут содержать статические элементы. Дополнительные сведения см. в разделе Статические классы и члены статических классов.
Вложенные типы
Класс, структура или запись могут быть вложены в другой класс, структуру или запись. Дополнительные сведения см. в разделе Вложенные типы.
Разделяемые типы
Вы можете разделить определение класса, структуры или метода на несколько файлов с кодом. Дополнительные сведения см. в статье Разделяемые классы и методы.
Инициализаторы объектов
Вы можете создавать и инициализировать объекты классов или структур, а также коллекции объектов, назначая значения связанным свойствам. Дополнительные сведения см. в разделе «Как инициализировать объекты с помощью инициализатора объектов».
Анонимные типы
В некоторых ситуациях нет смысла или пользы создавать именованный класс. В таких случаях можно использовать анонимные типы. Анонимные типы определяются их именованными элементами данных. Дополнительные сведения см. в разделе Анонимные типы.
Методы расширения
Вы можете «расширить» класс, даже не создавая производного класса. Для этого можно создать отдельный тип и вызывать его методы так, как если бы они принадлежали исходному типу. Дополнительные сведения см. в разделе «Методы расширения»).
Неявно типизированные локальные переменные
Внутри метода класса или структуры можно использовать неявное типизирование, чтобы компилятор самостоятельно определял тип переменной во время компиляции. Дополнительные сведения см. в var (справочник по C#).
Записи
В C# 9 появился тип record , ссылочный тип, который можно создать вместо класса или структуры. Записи — это классы со встроенным поведением для инкапсуляции данных в неизменяемых типах. В C# 10 представлен новый тип значения record struct . Запись ( record class или record struct ) предоставляет следующие возможности:
- краткий синтаксис для создания ссылочного типа с неизменяемыми свойствами;
- равенство значений. Две переменные типа записи равны, если у них одинаковые типы и равные значения в каждом поле обеих записей. Классы используют равенство ссылок: две переменные типа класса равны, если они ссылаются на один и тот же объект.
- Краткий синтаксис для обратимого изменения. Выражение with позволяет создать новый экземпляр записи, который является копией существующего экземпляра, но в котором изменены значения указанных свойств.
- Встроенное форматирование для отображения. Метод ToString выводит имя типа записи, а также имена и значения общих свойств.
- Поддержка иерархий наследования в классах записей. Классы записей поддерживают наследование. Структуры записей не поддерживают наследование.
Дополнительные сведения см. в статье Записи.
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
Си шарп структура это
Наряду с классами структуры представляют еще один способ создания собственных типов данных в C#. Более того многие примитивные типы, например, int, double и т.д., по сути являются структурами.
Определение структуры
Для определения структуры применяется ключевое слово struct :
После слова struct идет название структуры и далее в фигурных скобках размещаются элементы структуры — поля, методы и т.д.
Например, определим структуру, которая будет называться Person и которая будет представлять человека:
Как и классы, структуры могут хранить состояние в виде полей (переменных) и определять поведение в виде методов. Например, добавим в структуру Person пару полей и метод:
В данном случае определены две переменные — name и age для хранения соответственно имени и возраста человека и метод Print для вывода информации о человеке на консоль.
И как и в случае с классами, для обращения к функциональности структуры — полям, методам и другим компонентам структуры применяется точечная нотация — после объекта структуры ставится точка, а затем указывается компонент структуры:
объект.поле_структуры объект.метод_структуры(параметры_метода)
Создание объекта структуры
Инициализация с помощью конструктора
Для использования структуры ее необходмо инициализировать. Для инициализации создания объектов структуры, как и в случае с классами, применяется вызов конструктура с оператором new . Даже если в коде стуктуры не определено ни одного конструктора, тем не менее имеет как минимум один конструктор — конструктор по умолчанию, который генерируется компилятором. Этот конструктор не принимает параметров и создает объект структуры со значениями по умолчанию.
Например, создадим объект структуры Person с помощью конструктора по умолчанию:
Person tom = new Person(); // вызов конструктора // или так // Person tom = new(); tom.name = "Tom"; // изменяем значение по умолчанию в поле name tom.Print(); // Имя: Tom Возраст: 0 struct Person < public string name; public int age; public void Print() < Console.WriteLine($"Имя: Возраст: "); > >
В данном случае создается объект tom. Для его создания вызывается конструктор по умолчанию, который устанавливает значения по умолчанию для его полей. Для числовых данных это значение 0, поэтому поле age будет иметь значение 0. Для строк это значение null , которое указывает на отсутствие значения. Но далее, если поля доступны (а в данном случае поскольку они имеют модификатор public они доступны), мы можем изменить их значения. Так, здесь полю name присваивается строка «Tom». Соответственно при выполнении метода Print() мы получим следующий консольный вывод:
Непосредственная иницилизация полей
Если все поля структуры доступны (как в случае с полями структуры Person, который имеют модификатор public ), то структуру можно инициализировать без вызова конструктора. В этом случае необходимо присвоить значения всем полям структуры перед получением значений полей и обращением к методам структуры. Например:
Person tom; // не вызываем конструктор // инициализация полей tom.name = "Sam"; tom.age = 37; tom.Print(); // Имя: Sam Возраст: 37 struct Person < public string name; public int age; public void Print() < Console.WriteLine($"Имя: Возраст: "); > >
Инициализация полей по умолчанию
Стоит отметить, что начиная с версии C# 10, мы можем напрямую инициализировать поля структуры при их определении (до C# 10 это делать было нельзя):
Person tom = new Person(); tom.Print(); // Имя:Tom Возраст: 1 struct Person < // инициализация полей значениями по умолчанию - доступна с C#10 public string name = "Tom"; public int age = 1; public Person() < >public void Print() =>Console.WriteLine($"Имя: Возраст: "); >
Однако даже в этом случае, несмотря на значения по умолчанию, необходимо явно определить и вызывать конструктор, если мы хотим использовать эти значения.
Конструкторы структуры
Как и класс, структура может определять конструкторы. Например, добавим в структуру Person конструктор:
Person tom = new(); Person bob = new("Bob"); Person sam = new("Sam", 25); tom.Print(); // . Имя: Возраст: 0 bob.Print(); // Имя: Bob Возраст: 1 sam.Print(); // Имя: Sam Возраст: 25 struct Person < public string name; public int age; public Person(string name = "Tom", int age = 1) < this.name = name; this.age = age; >public void Print() => Console.WriteLine($"Имя: Возраст: "); >
В данном случае в структуре Person определен конструктор с двумя параметрами, для которых предоставлены значения по умолчания. Однако обратите внимание на создание первого объекта структуры:
Person tom = new(); // по прежнему используется конструктор без параметров по умолчанию tom.Print(); // . Имя: Возраст: 0
Здесь по-прежнему применяется конструктор по умолчанию, тогда как при инициализации остальных двух переменных структуры применяется явно определенный конструктор.
Однако начиная с версии C# 10 мы можем определить свой конструктор без параметров:
Person tom = new(); tom.Print(); // Имя: Tom Возраст: 37 struct Person < public string name; public int age; public Person() < name = "Tom"; age = 37; >public void Print() => Console.WriteLine($"Имя: Возраст: "); >
Стоит отметить, что до версии C# 11 при определении конструктора структуру в нем необходимо было инициализировать все поля структуры, начиная с версии C# 11 это делать необязательно.
В случае если нам необходимо вызывать конструкторы с различным количеством параметров, то мы можем, как и в случае с классами, вызывать их по цепочке:
Person tom = new(); Person bob = new("Bob"); Person sam = new("Sam", 25); tom.Print(); // Имя: Tom Возраст: 1 bob.Print(); // Имя: Bob Возраст: 1 sam.Print(); // Имя: Sam Возраст: 25 struct Person < public string name; public int age; public Person() : this("Tom") < >public Person(string name) : this(name, 1) < >public Person(string name, int age) < this.name = name; this.age = age; >public void Print() => Console.WriteLine($"Имя: Возраст: "); >
Консольный вывод программы:
Имя: Tom Возраст: 1 Имя: Bob Возраст: 1 Имя: Sam Возраст: 25
Инициализатор структуры
Также, как и для класса, можно использовать инициализатор для создания структуры:
Person tom = new Person < name = "Tom", age = 22 >; tom.Print(); // Имя: Tom Возраст: 22 struct Person < public string name; public int age; public void Print() =>Console.WriteLine($"Имя: Возраст: "); >
При использовании инициализатора сначала вызывается конструктор без параметров: если мы явным образом не определили конструктор без параметров, то вызывается конструктор по умолчанию. А затем его полям присваиваются соответствующие значения.
Копирование структуры с помощью with
Если нам необходимо скопировать в один объект структуры значения из другого с небольшими изменениями, то мы можем использовать оператор with :
Person tom = new Person < name = "Tom", age = 22 >; Person bob = tom with < name = "Bob" >; bob.Print(); // Имя: Bob Возраст: 22
В данном случае объект bob получает все значения объекта tom, а затем после оператора with в фигурных скобках указывается поля со значениями, которые мы хотим изменить.