Как создать класс в с
Перейти к содержимому

Как создать класс в с

  • автор:

Сведения об использовании классов и объектов в объектно-ориентированном программировании

В этом руководстве показано, как создать консольное приложение, и приведены основные объектно-ориентированные функции языка C#.

Предварительные требования

  • Мы рекомендуем Использовать Visual Studio для Windows или Mac. Вы можете скачать бесплатную версию на странице загрузок Visual Studio. Visual Studio включает пакет SDK для .NET.
  • Вы также можете использовать редактор Visual Studio Code. Вам потребуется установить последнюю версию пакета SDK для .NET отдельно.
  • Если вы предпочитаете другой редактор, необходимо установить последнюю версию пакета SDK для .NET.

Создание приложения

С помощью окна терминала создайте каталог с именем classes. В этом каталоге вы создадите приложение. Откройте этот каталог и введите в окне консоли dotnet new console . При помощи этой команды создается приложение. Откройте файл Program.cs. Он должен выглядеть так:

// See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!"); 

При работе с этим руководством вы создадите новые типы, представляющие банковский счет. Обычно разработчики определяют каждый класс в отдельном текстовом файле. Благодаря этому программой легче управлять, когда ее размер увеличивается. Создайте файл с именем BankAccount.cs в каталоге Classes .

Этот файл будет содержать определение банковского счета. Объектно-ориентированное программирование упорядочивает код, создавая типы в виде классов. Классы содержат код, который представляет отдельную сущность. Класс BankAccount представляет банковский счет. Этот код реализует определенные операции с помощью методов и свойств. Созданный в этом кратком руководстве банковский счет поддерживает следующий алгоритм работы:

  1. Представляет собой число из 10 цифр, которое однозначно определяет банковский счет.
  2. Содержит строку, в которой хранятся имена владельцев.
  3. Позволяет получить данные сальдо.
  4. Принимает депозиты.
  5. Принимает списания.
  6. Начальное сальдо должно было положительным.
  7. Снятие не может привести к отрицательному балансу.

Определение типа банковского счета

Сначала можно создать основы класса, который определяет такой режим работы. Создайте новый файл с помощью команды File:New. Присвойте ему имя BankAccount.cs. Добавьте в файл BankAccount.cs следующий код:

namespace Classes; public class BankAccount < public string Number < get; >public string Owner < get; set; >public decimal Balance < get; >public void MakeDeposit(decimal amount, DateTime date, string note) < >public void MakeWithdrawal(decimal amount, DateTime date, string note) < >> 

Прежде чем продолжить, рассмотрим созданный код. Объявление namespace предоставляет способ логического упорядочения кода. Это относительно небольшое руководство, поэтому весь код размещается в одном пространстве имен.

public class BankAccount определяет класс или тип, который вы создаете. Весь код в скобках < и >, который следует за объявлением класса, определяет состояние и поведение класса. Существует пять членов BankAccount класса. Первые три элемента представляют собой свойства. Свойства являются элементами данных и могут содержать код для запуска проверки или других правил. Последние два метода являются методами. Методы представляют собой блоки кода, которые выполняют только одну функцию. Имя каждого элемента должно содержать достаточно информации, чтобы разработчик мог понять, какие функции выполняет класс.

Открытие нового счета

Сначала нужно открыть банковский счет. Когда клиент открывает счет, он должен указать начальное сальдо и сведения о владельцах этого счета.

Создание нового объекта BankAccount типа означает определение конструктора , присваивающего эти значения. Конструктор — это член, имя которого совпадает с именем класса . Он используется для инициализации объектов этого типа класса. Добавьте указанный ниже конструктор в тип BankAccount . Добавьте следующий код непосредственно перед объявлением MakeDeposit :

public BankAccount(string name, decimal initialBalance)

Приведенный выше код определяет свойства создаваемого объекта путем включения this квалификатора. Этот квалификатор обычно является необязательным и опущен. Вы также могли написать:

public BankAccount(string name, decimal initialBalance)

Квалификатор this требуется, только если локальная переменная или параметр имеют то же имя, что и это поле или свойство. Квалификатор this опущен в оставшейся части этой статьи, если это не необходимо.

Конструкторы вызываются при создании объекта с помощью new . Замените строку Console.WriteLine(«Hello World!»); в файле Program.cs следующим кодом (замените своим именем):

using Classes; var account = new BankAccount("", 1000); Console.WriteLine($"Account was created for with initial balance."); 

Давайте выполним то, что уже создано. Если вы работаете в Visual Studio, выберите Запуск без отладки в меню Отладка. Если вы используете командную строку, введите dotnet run в том каталоге, где создали проект.

Вы заметили, что номер счета не указан? Нужно решить эту проблему. Номер счета следует назначить при создании объекта. Но создавать этот номер не входит в обязанности вызывающего. Код класса BankAccount должен иметь информацию о том, как присвоить номера новым счетам. Простой способ — начать с 10-значного числа. Увеличивайте его при создании каждого нового счета. Затем при создании объекта сохраните номер текущего счета.

Добавьте в класс BankAccount объявление члена. Поместите следующую строку кода после открывающей скобки < в начале класса BankAccount :

private static int s_accountNumberSeed = 1234567890; 

является accountNumberSeed элементом данных. Он имеет свойство private , то есть к нему может получить доступ только код внутри класса BankAccount . Таким образом общедоступные обязательства (например, получение номера счета) отделяются от закрытой реализации (способ создания номеров счетов). Это также static , что означает, что он является общим для всех BankAccount объектов. Значение нестатической переменной является уникальным для каждого экземпляра объекта BankAccount . является accountNumberSeed полем private static и, следовательно, имеет s_ префикс в соответствии с соглашениями об именовании C#. Обозначающее s static и _ обозначающее private поле. Добавьте две приведенные ниже строки в конструктор, чтобы назначить номер счета. Они должны располагаться за строкой с текстом this.Balance = initialBalance .

Number = s_accountNumberSeed.ToString(); s_accountNumberSeed++; 

Введите dotnet run , чтобы просмотреть результаты.

Создание депозитов и списаний

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

Начнем с создания нового типа, который представляет транзакцию. Транзакция — это простой тип, который не имеет никаких обязанностей. Ему нужно назначить несколько свойств. Создайте новый файл с именем Transaction.cs. Добавьте в этот файл следующий код:

namespace Classes; public class Transaction < public decimal Amount < get; >public DateTime Date < get; >public string Notes < get; >public Transaction(decimal amount, DateTime date, string note) < Amount = amount; Date = date; Notes = note; >> 
private List _allTransactions = new List(); 

Далее мы соответствующим образом вычислим Balance . Чтобы вычислить текущий баланс, нужно суммировать значения всех транзакций. В этом виде этот код позволяет получить только начальный баланс счета, поэтому необходимо обновить свойство Balance . В файле BankAccount.cs замените строку public decimal Balance < get; >следующим кодом:

public decimal Balance < get < decimal balance = 0; foreach (var item in _allTransactions) < balance += item.Amount; >return balance; > > 

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

Теперь реализуйте методы MakeDeposit и MakeWithdrawal . Эти методы применяют два последних правила: начальный баланс должен быть положительным, а любое снятие не должно создавать отрицательного баланса.

Эти правила вводят понятие исключений. Стандартным способом указания на то, что метод не может успешно завершить свою работу, является создание исключения. В типе исключения и связанном с ним сообщении описывается ошибка. В этом случае MakeDeposit метод создает исключение, если сумма депозита не превышает 0. Метод MakeWithdrawal создает исключение, если сумма вывода не больше 0 или если применение вывода приводит к отрицательному балансу. Добавьте следующий код после объявления списка _allTransactions :

public void MakeDeposit(decimal amount, DateTime date, string note) < if (amount var deposit = new Transaction(amount, date, note); _allTransactions.Add(deposit); > public void MakeWithdrawal(decimal amount, DateTime date, string note) < if (amount if (Balance - amount < 0) < throw new InvalidOperationException("Not sufficient funds for this withdrawal"); >var withdrawal = new Transaction(-amount, date, note); _allTransactions.Add(withdrawal); > 

Оператор throw создает исключение. Выполнение текущего блока завершается и управление передается в первый подходящий блок catch из стека вызовов. Вы добавите блок catch для тестирования этого кода немного позже.

Чтобы вместо непосредственного обновления сальдо добавлялась начальная транзакция, конструктор должен получить одно изменение. Так как вы уже написали метод MakeDeposit , вызовите его из конструктора. Готовый конструктор должен выглядеть так:

public BankAccount(string name, decimal initialBalance)

DateTime.Now — это свойство, которое возвращает текущие дату и время. Протестируйте этот код, добавив несколько депозитов и снятия средств в метод Main , следуя коду, который создает новый BankAccount :

account.MakeWithdrawal(500, DateTime.Now, "Rent payment"); Console.WriteLine(account.Balance); account.MakeDeposit(100, DateTime.Now, "Friend paid me back"); Console.WriteLine(account.Balance); 

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

// Test that the initial balances must be positive. BankAccount invalidAccount; try < invalidAccount = new BankAccount("invalid", -55); >catch (ArgumentOutOfRangeException e)

Оператор используется try-catch для пометки блока кода, который может вызывать исключения, и перехвата ожидаемых ошибок. Так же можно проверять код, который вызывает исключение при получении отрицательного баланса. Добавьте следующий код перед объявлением invalidAccount в Main методе :

// Test for a negative balance. try < account.MakeWithdrawal(750, DateTime.Now, "Attempt to overdraw"); >catch (InvalidOperationException e)

Сохраните файл и введите dotnet run для проверки.

Задача — регистрация всех транзакций

В завершение вы создадите метод GetAccountHistory , который создает string для журнала транзакций. Добавьте этот метод в тип BankAccount :

public string GetAccountHistory() < var report = new System.Text.StringBuilder(); decimal balance = 0; report.AppendLine("Date\t\tAmount\tBalance\tNote"); foreach (var item in _allTransactions) < balance += item.Amount; report.AppendLine($"\t\t\t"); > return report.ToString(); > 

Журнал использует класс для форматирования StringBuilder строки, содержащей одну строку для каждой транзакции. Код форматирования строки вы уже видели в этой серии руководств. В этом коде есть новый символ \t . Он позволяет вставить вкладку для форматирования выходных данных.

Добавьте следующую строку, чтобы проверить его в файле Program.cs:

Console.WriteLine(account.GetAccountHistory()); 

Снова выполните программу, чтобы просмотреть результаты.

Следующие шаги

Если у вас возникли проблемы, изучите исходный код для этого руководства, размещенный в репозитории GitHub.

Дополнительные сведения об этих понятиях см. в следующих статьях:

  • Инструкции выбора
  • Инструкции итерации

Совместная работа с нами на GitHub

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

Общие сведения о классах

Тип, определенный как , class является ссылочным типом. Во время выполнения при объявлении переменной ссылочного типа переменная содержит значение null , пока вы явно не создадите экземпляр класса с помощью new оператора или не назначите ему объект совместимого типа, который может быть создан в другом месте, как показано в следующем примере:

//Declaring an object of type MyClass. MyClass mc = new MyClass(); //Declaring another object of the same type, assigning it the value of the first object. MyClass mc2 = mc; 

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

Объявление классов

Классы объявляются с помощью class ключевое слово за которым следует уникальный идентификатор, как показано в следующем примере:

//[access modifier] - [class] - [identifier] public class Customer < // Fields, properties, methods and events go here. >

Дополнительный модификатор class доступа предшествует ключевое слово. Так как public используется в этом случае, любой пользователь может создавать экземпляры этого класса. За именем класса следует ключевое слово class . Имя класса должно быть допустимым именем идентификатора C#. Оставшаяся часть определения — это тело класса, в котором задаются данные и поведение. Поля, свойства, методы и события в классе собирательно называются членами класса.

Создание объектов

Хотя они иногда используются взаимозаменяемо, класс и объект — это разные вещи. Класс определяет тип объекта, но сам по себе он не является объектом. Объект — это конкретная сущность, основанная на классе, которую иногда называют экземпляром класса.

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

Customer object1 = new Customer(); 

При создании экземпляра класса ссылка на объект передается программисту. В предыдущем примере object1 представляет собой ссылку на объект, который основан на Customer . Эта ссылка ссылается на новый объект , но не содержит сами данные объекта. Фактически, можно создать ссылку на объект без создания собственно объекта:

Customer object2; 

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

Customer object3 = new Customer(); Customer object4 = object3; 

В этом коде создаются две ссылки на объект, которые указывают на один и тот же объект. Таким образом, любые изменения объекта, выполненные посредством object3 , отражаются при последующем использовании object4 . Поскольку на объекты, основанные на классах, указывают ссылки, классы называют ссылочными типами.

Конструкторы и инициализация

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

  • Принятие значений по умолчанию
  • Инициализаторы полей
  • Параметры конструктора
  • Инициализаторы объектов

Каждый тип .NET имеет значение по умолчанию. Как правило, это значение равно 0 для числовых типов и null для всех ссылочных типов. Вы можете использовать это значение по умолчанию, если это целесообразно в приложении.

Если значение по умолчанию .NET не является правильным, можно задать начальное значение с помощью инициализатора поля:

public class Container < // Initialize capacity field to a default value of 10: private int _capacity = 10; >

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

public class Container < private int _capacity; public Container(int capacity) =>_capacity = capacity; > 

Начиная с C# 12, можно определить основной конструктор как часть объявления класса:

public class Container(int capacity)

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

Вы также можете использовать модификатор required для свойства и разрешить вызывающим объектам использовать инициализатор объекта для задания начального значения свойства:

public class Person < public required string LastName < get; set; >public required string FirstName < get; set; >> 

Добавление required ключевое слово требует, чтобы вызывающие объекты должны задавать эти свойства как часть new выражения:

var p1 = new Person(); // Error! Required properties not set var p2 = new Person() < FirstName = "Grace", LastName = "Hopper" >; 

Наследование классов

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

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

public class Manager : Employee < // Employee fields, properties, methods and events are inherited // New Manager fields, properties, methods and events go here. >

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

Класс в C# может напрямую наследовать только от одного базового класса. Однако поскольку базовый класс может сам наследовать от другого класса, класс может косвенно наследовать несколько базовых классов. Кроме того, класс может напрямую реализовать несколько интерфейсов. Дополнительные сведения см. в разделе Интерфейсы.

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

Определения классов можно разделить между различными исходными файлами. Дополнительные сведения см. в разделе Разделяемые классы и методы.

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

Совместная работа с нами на GitHub

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

Классы

Класс представляет собой шаблон, по которому определяется форма объекта. В нем указываются данные и код, который будет оперировать этими данными. В C# используется спецификация класса для построения объектов, которые являются экземплярами класса. Следовательно, класс, по существу, представляет собой ряд схематических описаний способа построения объекта. При этом очень важно подчеркнуть, что класс является логической абстракцией. Физическое представление класса появится в оперативной памяти лишь после того, как будет создан объект этого класса.

Классы и структуры — это, по сути, шаблоны, по которым можно создавать объекты. Каждый объект содержит данные и методы, манипулирующие этими данными.

Общая форма определения класса

При определении класса объявляются данные, которые он содержит, а также код, оперирующий этими данными. Если самые простые классы могут содержать только код или только данные, то большинство настоящих классов содержит и то и другое.

Вообще говоря, данные содержатся в членах данных, определяемых классом, а код — в функциях-членах. Следует сразу же подчеркнуть, что в C# предусмотрено несколько разновидностей членов данных и функций-членов:

Структура классов в C#

Данные-члены

Данные-члены — это те члены, которые содержат данные класса — поля, константы, события. Данные-члены могут быть статическими (static). Член класса является членом экземпляра, если только он не объявлен явно как static. Давайте рассмотрим виды этих данных:

Поля (field)

Это любые переменные, ассоциированные с классом.

Константы

Константы могут быть ассоциированы с классом тем же способом, что и переменные. Константа объявляется с помощью ключевого слова const. Если она объявлена как public, то в этом случае становится доступной извне класса.

События

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

Функции-члены

Функции-члены — это члены, которые обеспечивают некоторую функциональность для манипулирования данными класса. Они включают методы, свойства, конструкторы, финализаторы, операции и индексаторы:

Методы (method)

Это функции, ассоциированные с определенным классом. Как и данные-члены, по умолчанию они являются членами экземпляра. Они могут быть объявлены статическими с помощью модификатора static.

Свойства (property)

Это наборы функций, которые могут быть доступны клиенту таким же способом, как общедоступные поля класса. В C# предусмотрен специальный синтаксис для реализации чтения и записи свойств для классов, поэтому писать собственные методы с именами, начинающимися на Set и Get, не понадобится. Поскольку не существует какого-то отдельного синтаксиса для свойств, который отличал бы их от нормальных функций, создается иллюзия объектов как реальных сущностей, предоставляемых клиентскому коду.

Конструкторы (constructor)

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

Финализаторы (finalizer)

Вызываются, когда среда CLR определяет, что объект больше не нужен. Они имеют то же имя, что и класс, но с предшествующим символом тильды. Предсказать точно, когда будет вызван финализатор, невозможно.

Операции (operator)

Это простейшие действия вроде + или -. Когда вы складываете два целых числа, то, строго говоря, применяете операцию + к целым. Однако C# позволяет указать, как существующие операции будут работать с пользовательскими классами (так называемая перегрузка операции).

Индексаторы (indexer)

Позволяют индексировать объекты таким же способом, как массив или коллекцию.

Класс создается с помощью ключевого слова class. Ниже приведена общая форма определения простого класса, содержащая только переменные экземпляра и методы:

class имя_класса < // Объявление переменных экземпляра. доступ тип переменная1; доступ тип переменная2; //. доступ тип переменнаяN; // Объявление методов. доступ возращаемый_тип метод1 (параметры) < // тело метода >доступ возращаемый_тип метод2 (параметры) < // тело метода >//. . . доступ возращаемый_тип методN(параметры) < // тело метода >>

Обратите внимание на то, что перед каждым объявлением переменной и метода указывается доступ. Это спецификатор доступа, например public, определяющий порядок доступа к данному члену класса. Члены класса могут быть как закрытыми (private) в пределах класса, так открытыми (public), т.е. более доступными. Спецификатор доступа определяет тип разрешенного доступа. Указывать спецификатор доступа не обязательно, но если он отсутствует, то объявляемый член считается закрытым в пределах класса. Члены с закрытым доступом могут использоваться только другими членами их класса.

Давайте разберем пример создания класса, описывающего характеристики пользователя:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 < class UserInfo < // Поля класса public string Name, Family, Adress; public byte Age; // Метод, выводящий в консоль контактную информацию public void writeInConsoleInfo(string name, string family, string adress, byte age) < Console.WriteLine("Имя: \nФамилия: \nМестонахождение: \nВозраст: \n", name, family, adress, age); > > class Program < static void Main(string[] args) < // Создаем объект типа UserInfo UserInfo myInfo = new UserInfo(); myInfo.Name = "Alexandr"; myInfo.Family = "Erohin"; myInfo.Adress = "ViceCity"; myInfo.Age = 26; // Создадим новый экземпляр класса UserInfo UserInfo myGirlFriendInfo = new UserInfo(); myGirlFriendInfo.Name = "Elena"; myGirlFriendInfo.Family = "Korneeva"; myGirlFriendInfo.Adress = "ViceCity"; myGirlFriendInfo.Age = 22; // Выведем информацию в консоль myInfo.writeInConsoleInfo(myInfo.Name, myInfo.Family, myInfo.Adress, myInfo.Age); myGirlFriendInfo.writeInConsoleInfo(myGirlFriendInfo.Name,myGirlFriendInfo.Family,myGirlFriendInfo.Adress,myGirlFriendInfo.Age); Console.ReadLine(); >> >

В данном примере определяется новый пользовательский класс UserInfo, который содержит 4 поля и 1 метод, которые являются открытыми (т.е. содержат модификатор доступа public). В методе Main() создаются два экземпляра этого класса: myInfo и myGirlFriendInfo. Затем инициализируются поля данных экземпляров и вызывается метод writeInConsoleInfo().

Прежде чем двигаться дальше, рассмотрим следующий основополагающий принцип: у каждого объекта имеются свои копии переменных экземпляра, определенных в его классе. Следовательно, содержимое переменных в одном объекте может отличаться от их содержимого в другом объекте. Между обоими объектами не существует никакой связи, за исключением того факта, что они являются объектами одного и того же типа. Так, если имеются два объекта типа UserInfo, то у каждого из них своя копия переменных Name, Family, Age и Adress, а их содержимое в обоих объектах может отличаться:

Классы и объекты

Класс – основной тип данных языка C#. Класс представляет собой конструкцию, которая объединяет поля, свойства и методы. Класс является определением для создания объектов или экземпляров класса.

[modifiers] class ClassName < //тело класса > 

В начале идет модификатор доступа, а после ключевого слова class, имя класса, в фигурных скобках находиться тело класса, которое может содержать поля, свойства и методы – члены класса.

Простой пример объявления класса для хранения данных о пользователе:

public class User < public string UserName; public byte UserAge; > 

Для создания экземпляра класса используется оператор new:

User u = new User(); 

Члены класса

Класс может содержать в себе следующие члены:

  • Конструкторы;
  • Константы;
  • Поля;
  • Методы;
  • Свойства;
  • Операторы;
  • Вложенные типы данных;
  • Деструкторы.

Доступ к членам экземпляра класса осуществляется через оператор “.”, например u.UserAge = 21;

Модификаторы доступа

Модификатор доступа – определяет откуда можно обращаться к классу или его членам.

В языке C# доступны следующие уровни доступа:

  • public – максимально доступный уровень, не налагает никаких ограничений;
  • protected – доступ разрешен из текущего класса или его наследников;
  • internal – доступ ограничен текущей сборкой(в пределах программы, библиотеки);
  • protected internal – комбинация из предыдущих двух модификаторов;
  • private – доступ разрешен только в текущем классе;
  • private protected – доступ разрешен в текущем классе и классах наследниках расположенных в той же сборке.

Если классу или члену не задан модификатор доступа, то устанавливается модификатор по умолчанию internal для класса и private для членов.

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

Конструктор

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

Пример конструктора класса:

public class TrackPoint < //публичные поля public float X; public float Y; //конструктор public TrackPoint(float x, float y) < //инициализация полей X = x; Y = y; > > 

Сейчас при создании объекта класса TrackPoint необходимо передавать в конструктор аргументы:

var tp = new TrackPoint(2f, 3f); 

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

public class RGBColor < //публичные поля public int Red; public int Green; public int Blue; //конструктор без параметров public RGBColor( ) < >//конструктор с опциональными параметрами public RGBColor(int r, int g = 0, int b = 0) < Red = r; Green = g; Blue = b; >> 

Создание экземпляров класса:

var c1 = RGBColor(); var c2 = RGBColor(10, 20); 

Начиная с 7.0 версии языка C# конструктор c одним выражением можно записать в сокращенной форме:

public class Dog < public string Name; public uint Weight; //сокращенная форма записи public Dog(string n) => Name = n; //в конструкторе только одно выражение public Dog(string n, uint w) => SetParameters(n, w); //конструктор вызывает метод(это тоже одна операция) private void SetParameters(string n, uint w) < Name = n; Weight = w; >> 
Ключевое слово this

this – указывает на текущий экземпляр класса. Обычно используется для разделения параметров конструктора от полей с такими же названиями:

public class Worker < private string workerName; public Worker(string workerName) < //полю класса будет присвоено значение аргумента конструктора this.workerName = workerName; > > 

Также ключевое слово this может быть использовано для вызова конструктора класса:

protected class BlogPage < string title; uint year; //вызывает второй конструктор со строковым аргументом protected BlogPage( ) : this("Draft page") < >//вызывает третий передавая заголовок и год по умолчанию protected BlogPage(string title) : this(title, 2019) < >protected BlogPage(string title, uint year) < this.title = title; this.year = year; > > 

Создание экземпляров BlogPage:

var page1 = new BlogPage(); //заголовок - Draft page, год 2019 var page2 = new BlogPage("My Site");// My Site 2019 var page3 = new BlogPage("First article", 2018);// First article 2018 

Поля и константы

Поля класса – это переменные которые объявлены внутри класса. Не рекомендуется использовать публичные поля, доступ к ним должен осуществляться посредством свойств и методов, а инициализация обычно делается из конструктора.

Используйте поля с модификаторами доступа private или protected, использование public полей является плохой практикой.

Константы – это идентификаторы, значение которых задается во время компиляции программы, и не может быть изменено в процессе выполнения приложения.

internal class CircleFigure < //константа класса internal const double Pi = 3.1415; //приватное поле private double r; internal CircleFigure(double radius) < r = radius; >//получение данных поля посредством метода internal double GetRadius( ) => r; //метод для вычисления площади круга internal double CalculateArea( ) => Pi * r * r; > 

Свойства

Свойство – это член, который предоставляет механизм чтения и записи данных в поле класса. Внешне свойства не отличаются от полей, однако они являются специальными методами доступа, которые вызываются для чтения и изменения данных.

  • Свойства предоставляют доступ к данным, при этом скрывают механизм проверки и получения значений;
  • Метод get – вызывается при чтении значения свойства, может содержать обработку данных перед возвратом;
  • Метод set – вызывается при присвоении значения свойству, может использоваться для проверки значения. В теле set доступно ключевое слово value, которое содержит присвоенное свойству значение;

Используя варианты get и set можно создавать разные уровни доступа:

  • get и set – чтение и запись;
  • get – только чтение;
  • set – только запись.

Рассмотрим пример программы для вычисления площади прямоугольника:

using System; public class Rectangle < //приватные поля private uint a; private uint b; private string n; //сторона А public uint SideA < get < return a; > set < //проверка значения перед присваиванием if (value > 0) a = value; else Console.WriteLine("Ошибка А == 0"); > > //сторона В public uint SideB < get < return b; > set < //проверка значения перед присваиванием if (value > 0) b = value; else Console.WriteLine("Ошибка В == 0"); > > //название прямоугольника //свойство с доступом только для записи public string Name < set < n = value; > > //площадь прямоугольника //свойство с доступом только для чтения public uint Area < //обработка перед возвращением get < return a * b; > > //метод выводит на экран данные о фигуре public void Print( ) < Console.WriteLine($"  x Area = "); > > class Program < static void Main(string[] args) < var r = new Rectangle(); r.Name = "ABCD"; r.SideA = 0; //Выводится сообщение "Ошибка А == 0" r.SideA = 9; r.SideB = 7; r.Print(); //ABCD 9x7 Area = 63 Console.ReadLine(); > > 

C# поддерживает инициализацию полей и свойств класса при создании объекта:

var rec = new Rectangle < Name = "NMKL", SideA = 2, SideB = 4 >; 

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

protected string ComputerName < get; set; > 

Начиная с C# версии 6.0, автосвойства можно инициализировать подобно полям:

protected int CurrentYear< get; set; > = 2019; 

В той же версии языка стала доступна сокращенная форма записи свойств только для чтения:

public class Human < private string firstName; private string lastName; public Human(string first, string last) < firstName = first; lastName = last; >//свойство с доступом для чтения public string FullName => $"  "; > 

В C# версии 7.0 методы get и set можно записывать через оператор определения тела выражения=>“:

private ulong t; public ulong TotalCount < get => t; set => t = value; > 

Вложенные типы данных

Класс может содержать в себе другие классы(nested classes), структуры или перечисления.

Рассмотрим класс с вложенными типами

internal class MainClass < internal enum SelectedColor < Black, White, Gray >internal class Circle < internal double Radius get; set;> > > 

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

var c = new MainClass.Circle < Radius = 10 >; var w = MainClass.SelectedColor.White; 

Правила именования

Имена классов и его членов могут быть любыми, однако для лучшей читабельности кода, необходимо использовать Camel Case и Pascal Case нотации.

PascalCase – это стиль написания имен, при котором составные слова названия имени пишутся слитно, и каждое новое слово начинается с большой буквы. Пример: UserAgent, CalculatePerimeter, UserArray. Используется для названий классов, констант, публичных полей и свойств, а также именования всех методов.

CamelCase (верблюжья нотация) – стиль повторяет паскаль нотацию, только начинается с маленькой буквы. Пример: tempValue, cycleCounter. Используется для локальных переменных и констант.

Всем членам желательно давать имена описывающие функционал за который они отвечают.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *