Когда в программе появляются товар, пользователь, заказ или платеж, отдельных переменных быстро становится мало. Класс помогает собрать связанные данные и поведение в одну модель. В этом уроке мы создадим Product, добавим свойства, constructor и метод расчета итоговой цены
Никакой тяжелой ООП-теории на старте. Только пример, который можно запустить и изменить
Что получится в конце
Мы напишем класс:
public class Product
{
public string Name { get; }
public decimal Price { get; }
public int Quantity { get; }
public Product(string name, decimal price, int quantity)
{
Name = name;
Price = price;
Quantity = quantity;
}
public decimal Total()
{
return Price * Quantity;
}
}
И используем его в Program.cs:
var product = new Product("Книга по C#", 1200m, 2);
Console.WriteLine($"Товар: {product.Name}");
Console.WriteLine($"Итог: {product.Total()}");
Создаем проект
dotnet new console -n CSharpClasses
cd CSharpClasses
Откройте Program.cs и вставьте полный пример:
var product = new Product("Книга по C#", 1200m, 2);
Console.WriteLine($"Товар: {product.Name}");
Console.WriteLine($"Количество: {product.Quantity}");
Console.WriteLine($"Итог: {product.Total()}");
public class Product
{
public string Name { get; }
public decimal Price { get; }
public int Quantity { get; }
public Product(string name, decimal price, int quantity)
{
Name = name;
Price = price;
Quantity = quantity;
}
public decimal Total()
{
return Price * Quantity;
}
}
Запуск:
dotnet run
Ожидаемый вывод:
Товар: Книга по C#
Количество: 2
Итог: 2400
Что такое class
Строка:
public class Product
создает собственный тип Product. После этого можно создавать объекты:
var product = new Product("Книга по C#", 1200m, 2);
Класс описывает форму объекта: какие данные у него есть и какие действия он умеет выполнять
В нашем случае товар хранит название, цену и количество, а еще умеет считать итог через метод Total
Свойства вместо публичных полей
Свойство:
public string Name { get; }
похоже на поле, но дает больше контроля. Здесь есть только get, значит снаружи можно читать Name, но нельзя менять его после создания объекта
Такой код сработает:
Console.WriteLine(product.Name);
А такой нет:
product.Name = "Новое название";
Для первого примера это полезное ограничение: объект создается с понятными значениями и дальше не меняется случайно
Constructor
Constructor вызывается при создании объекта:
public Product(string name, decimal price, int quantity)
{
Name = name;
Price = price;
Quantity = quantity;
}
Он принимает значения и раскладывает их по свойствам. Поэтому вызов:
new Product("Книга по C#", 1200m, 2)
передает name, price, quantity в constructor
Символ m в 1200m означает decimal literal. Для денег decimal обычно подходит лучше, чем double
Метод Total
Метод:
public decimal Total()
{
return Price * Quantity;
}
описывает действие, связанное с товаром. Можно было считать итог прямо в Program.cs, но метод делает код выразительнее:
product.Total()
читается как «итог этого товара»
Если логика расчета изменится, ее нужно будет менять в одном месте внутри класса
Добавляем скидку
Расширим класс:
public decimal TotalWithDiscount(decimal discountPercent)
{
var discount = Total() * discountPercent / 100;
return Total() - discount;
}
Использование:
Console.WriteLine($"Итог со скидкой: {product.TotalWithDiscount(10)}");
Здесь метод TotalWithDiscount переиспользует Total, а не дублирует расчет Price * Quantity. Это маленький пример нормальной организации логики
Когда класс пока не нужен
Класс не стоит создавать ради каждого числа или строки. Если у вас один короткий расчет в Program.cs, отдельный класс может только усложнить чтение
Класс нужен, когда данные явно связаны и будут передаваться вместе: товар, заказ, пользователь, настройка, результат API. Если появляется несколько переменных с общим смыслом, это хороший кандидат на класс
Частые ошибки
The name 'Product' does not exist. Класс не добавлен в файл, находится не в том namespace или проект не пересобран
There is no argument given that corresponds to the required parameter. Constructor требует параметры, а вы вызвали new Product() без них
Cannot assign to property because it is read only. У свойства есть только get. Чтобы менять значение после создания, нужен set, но добавляйте его осознанно
decimal и double смешались. Значение 1200m имеет тип decimal, а 1200.0 — double. Для финансового примера держите decimal
Что может быть еще интересно по этой теме
Чем class отличается от struct? Класс — ссылочный тип, struct — значимый тип. Для первого прикладного моделирования в C# чаще начинайте с class
Почему свойства начинаются с большой буквы? Это стандарт именования в C#: публичные свойства и методы обычно пишут в PascalCase
Можно ли вынести Product в отдельный файл? Да. В реальном проекте класс обычно живет в Product.cs, а Program.cs остается точкой запуска
Нужно ли сразу учить наследование? Нет. Сначала свойства, constructor, методы и коллекции. Наследование не должно быть первым инструментом новичка
Что открыть дальше
- Типы, переменные и строки в C# — если
decimal,intиstringеще путаются. - List, Dictionary и LINQ в C# на живом примере — следующий шаг после одного объекта.
- JSON и файлы в C#: читаем настройки проекта — классы пригодятся для сериализации.
- ASP.NET Core Minimal API: первый endpoint — там модели используются в API-ответах.



