Класс – основной тип данных языка 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($"{n} {a}x{b} Area = {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 => $"{firstName} {lastName}";
}
В 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. Используется для локальных переменных и констант.
Всем членам желательно давать имена описывающие функционал за который они отвечают.