Class program c что это
Перейти к содержимому

Class program c что это

  • автор:

Объекты — создание экземпляров типов

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

Поведение статических типов отличается от описанного здесь поведения. Дополнительные сведения см. в статье Статические классы и члены статических классов.

Экземпляры структуры и Экземпляры классов

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

Экземпляры классов создаются с помощью new оператора . В приведенном ниже примере Person является типом, а person1 и person2 — экземплярами или объектами этого типа.

using System; public class Person < public string Name < get; set; >public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >// Other properties, methods, events. > class Program < static void Main() < Person person1 = new Person("Leopold", 6); Console.WriteLine("person1 Name = Age = ", person1.Name, person1.Age); // Declare new person, assign person1 to it. Person person2 = person1; // Change the name of person2, and person1 also changes. person2.Name = "Molly"; person2.Age = 16; Console.WriteLine("person2 Name = Age = ", person2.Name, person2.Age); Console.WriteLine("person1 Name = Age = ", person1.Name, person1.Age); > > /* Output: person1 Name = Leopold Age = 6 person2 Name = Molly Age = 16 person1 Name = Molly Age = 16 */ 

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

using System; namespace Example < public struct Person < public string Name; public int Age; public Person(string name, int age) < Name = name; Age = age; >> public class Application < static void Main() < // Create struct instance and initialize by using "new". // Memory is allocated on thread stack. Person p1 = new Person("Alex", 9); Console.WriteLine("p1 Name = Age = ", p1.Name, p1.Age); // Create new struct object. Note that struct can be initialized // without using "new". Person p2 = p1; // Assign values to p2 members. p2.Name = "Spencer"; p2.Age = 7; Console.WriteLine("p2 Name = Age = ", p2.Name, p2.Age); // p1 values remain unchanged because p2 is copy. Console.WriteLine("p1 Name = Age = ", p1.Name, p1.Age); > > /* Output: p1 Name = Alex Age = 9 p2 Name = Spencer Age = 7 p1 Name = Alex Age = 9 */ > 

Память для p1 и p2 выделена в стеке потока. Эта память освобождается вместе с типом или методом, в котором она объявлена. Эта одна из причин того, почему структуры копируются при присваивании. Напротив, при выходе всех ссылок на объект из области действия среда CLR автоматически освобождает память (выполняет сборку мусора), выделенную для экземпляра класса. Детерминированное уничтожение объекта класса, как в C++, невозможно. Дополнительные сведения о сборке мусора в .NET см. в статье Сборка мусора.

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

Идентификация объектов и равенство значений

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

  • Чтобы определить, ссылаются ли два экземпляра класса на одно расположение в памяти (то есть имеют одинаковый идентификатор), воспользуйтесь статическим методом Object.Equals. (System.Object является неявным базовым классом для всех типов значений и ссылочных типов, включая структуры и классы, определенные пользователем.)
  • Чтобы определить, имеют ли поля экземпляра в двух экземплярах структуры одинаковые значения, воспользуйтесь методом ValueType.Equals. Так как все структуры неявно наследуются от System.ValueType, метод можно вызвать непосредственно в объекте, как показано в следующем примере:

// Person is defined in the previous example. //public struct Person // < // public string Name; // public int Age; // public Person(string name, int age) // < // Name = name; // Age = age; // >//> Person p1 = new Person("Wallace", 75); Person p2 = new Person("", 42); p2.Name = "Wallace"; p2.Age = 75; if (p2.Equals(p1)) Console.WriteLine("p2 and p1 have the same values."); // Output: p2 and p1 have the same values. 

Связанные разделы

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

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

Class program c что это

Класс — это тип, создаваемый пользователем. Классы являются основным строительным материалом программ, написанных на языке C#. Если в C++ классы используют только в случае необходимости (их можно и вообще не применять!), то в C# всё построено на классах . Даже простейшая программа типа «Здравствуй, мир!» содержит в себе один класс. Обычно же программы на C# состоят из большого количества пользовательских классов.

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

Понятие класса является основой концепции объектно-ориентированного программирования (ООП) .

ООП базируется на т рёх основных принципах : инкапсуляция, наследование и полиморфизм.

Инкапсуляция — это объединение под одним общим именем в виде класса данных (их часто называют полями) и методов по обработки этих данных. Вне класса по-умолчанию все поля и методы просто недоступны. Делается это с целью исключения ошибочного изменения полей «чужими» методами.

Именно благодаря такому искусственному сокрытию данных (и часто — методов) появляется возможность разработки больших программных комплексов (на миллионы строк кода), которые могут быть вполне работоспособны.

Принцип наследования — второй по значимости среди основных идей ООП. Благодаря наследованию мы можем на основе одного класса (класса-предка) спроектировать другой класс (класс-наследник), который унаследует от своего предка всё, что нам потребуется. Естественно, в классе-наследнике появятся какие-то новые свойства (поля, методы), которые расширят возможности класса-наследника. Но при этом нам не требуется заново разрабатывать тот программный код, который был в классе-предке. Понятно, что принцип наследования может существенно сократить сроки разработки новых программ и повысить их надёжность.

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

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

Рассмотрев вкратце основные идеи ООП, далее перейдём к более подробному их изучению. И начнём с главного — как создавать и использовать классы.

Структура класса и порядок его использования

Формально любой класс можно описать таким образом:

атрибуты class имя_класса : предки

атрибуты — одно из ключевых слов, определяющих доступность класса (например, public , protected , private ), либо какие-то другие базовые свойства класса ( static — статичный класс, abstract — абстрактный класс, sealed — бесплодный класс);

имя_класса — задаётся по общим правилам (как для любого идентификатора, например, как для имени переменной);

предки — необязательный параметр. Класс, который мы создаём, может быть наследником какого-то другого класса (но только одного!) и наследником любого количества интерфейсов (об интерфейсах речь пойдёт далее);

члены_класса — это данные, инкапсулированные в классе, и методы по их обработке.

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

имя_класса переменная = new имя_класса () ;

Здесь с помощью операции new создаётся объект нашего класса. В скобках как после имени класса, так и после названия метода возможны какие-либо параметры (если это определено в классе).

Вызов метода возможен только с использованием операции доступа (операция «точка». Указываем название переменной, имеющей тип данного класса, затем ставим точку и только потом пишем имя метода с возможными фактическими параметрами.

Пример простого класса

Для большей ясности сразу же рассмотрим пример с небольшим классом.

Пример . Создать класс, моделирующий работу с треугольником (задаются три стороны a , b и c и вычисляется площадь треугольника s ).

Возможная реализация программы:

double a, b, c; // стороны треугольника

// метод для ввода данных

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

В этом руководстве показано, как создать консольное приложение, и приведены основные объектно-ориентированные функции языка 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 program c что это

Точкой входа в программу на языке C# является метод Main. Именно с этого метода начинается выполнение программы на C#. И программа на C# должна обязательно иметь метод Main . Однако может возникнуть вопрос, какой еще метод Main, если, например, Visual Studio 2022 по умолчанию создает проект консольного приложения со следующим кодом:

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

И эта программа никаких методов Main не содержит, но при этом нормально выполняется и выводит на консоль строку «Hello, World!», как и запланировано. Это так называемая программа верхнего уровня (top-level program). А вызов Console.WriteLine(«Hello, World!») представляет инструкцию вехнего уровня (top-level statement)

Однако в реальности этот код неявно помещается компилятором в метод Main, который, в свою очередь, помещается в класс Program. В действительности название класса может быть любым (как правило, это класс Program, собственно поэтому генерируемый по умолчанию файл кода называется Program.cs ). Но метод Main является обязательной частью консольного приложения. Поэтому выше представленный код фактически эквивалентен следующей программе:

class Program < static void Main(string[] args) < // See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!"); >>

Определение метода Main обязательно начинается с модификатора static , которое указывает, что метод Main — статический. Позже мы подробнее разберем, что все это значит.

Возвращаемым типом метода Main обязательно является тип void . Кроме того, в качестве параметра он принимает массив строк — string[] args — в реальной программе это те параметры, через которые при запуске программы из консоли мы можем передать ей некоторые значения. Внутри метода располагаются действия, которые выполняет программа.

До Visual Studio 2022 все предыдущие студии создавали по умолчанию примерно такой код. Но начиная с Visual Studio 2022 нам необязательно вручную определять класс Program и в нем метод Main — компилятор генерирует их самостоятельно.

Если мы определяем какие-то переменные, константы, методы и обращаемся к ним, они помещаются в метод Main. Например, следующая программа верхнего уровня

string hello = «Hello METANIT.COM»; Print(hello); void Print(string message)

будет аналогична следующей программе:

class Program < static void Main(string[] args) < string hello = "Hello METANIT.COM"; Print(hello); void Print(string message) < Console.WriteLine(message); >> >

Если определяются новые типы, например, классы, то они помещаются вне класса Program. Например, код:

Person tom = new(); tom.SayHello(); class Person < public void SayHello() =>Console.WriteLine("Hello"); >

будет аналогичен следующему

class Program < static void Main(string[] args) < Person tom = new(); tom.SayHello(); >> class Person < public void SayHello() =>Console.WriteLine("Hello"); >

Однако надо учитывать, что опредления типов (в частности классов) должны идти в конце файла после инструкций верхнего уровня. То есть:

// инструкции верхнего уровня (top-level statements) Person tom = new(); tom.SayHello(); // определение класса идет после инструкций верхнего уровня class Person < public void SayHello() =>Console.WriteLine("Hello"); >

Таким образом, мы можем продолжать писать программы верхнего уровня без явного определения метода Main. Либо мы можем явным образом определить метод Main и класс Program:

top-level programs in C# и Visual Studio 2022

И этот код будет выполняться аналогичным образом, как если бы мы не использовали класс Program и метод Main.

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

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