<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Egor</title><subtitle>Minsk | Freelance recruiter | BSUIR student | Learning C# .NET</subtitle><author><name>Egor</name></author><id>https://teletype.in/atom/dalival</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/dalival?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@dalival?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dalival"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/dalival?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-15T16:16:52.848Z</updated><entry><id>dalival:TMS.Net07</id><link rel="alternate" type="text/html" href="https://teletype.in/@dalival/TMS.Net07?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=dalival"></link><title>TeachMeSkills C# .NET</title><published>2021-01-27T18:36:27.099Z</published><updated>2021-02-17T23:37:39.636Z</updated><summary type="html">&lt;img src=&quot;https://teletype.in/files/2a/63/2a631ead-2fab-4a1f-80db-3a8160dff209.jpeg&quot;&gt;Заметка: заметки никак не связаны с основным конспектом. Можно воспользоваться поиском по слову Заметка, чтобы найти все инсайты.</summary><content type="html">
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; заметки никак не связаны с основным конспектом. Можно воспользоваться поиском по слову Заметка, чтобы найти все инсайты.&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;27.01&lt;br /&gt;Занятие 2&lt;/h2&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; Stepik – сайт с курсами. Проходишь пару уроков, и тебе присылают лицензию на IDE от JetBrains. Она удобнее вижлы. Для C# называется Rider. В него встроен решарпер – автоматическая проверка кода на сложные ошибки.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt;&lt;br /&gt;Ctrl K C – закомментить код&lt;br /&gt;Ctrl K U – раскомментить код&lt;br /&gt;Ctrl K F – форматировать код&lt;/p&gt;
  &lt;p&gt;Самые ходовые типы:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;int&lt;/strong&gt; – целое число. Всегда 4 байта, независимо от архитектуры, в отличие от других языков.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;double&lt;/strong&gt; – дробное число, только надо в конце d ставить, например double a = 10.56d. UPD: букву d писать необязательно.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;decimal&lt;/strong&gt; – для точных вычислений, например денег. В конце ставить m.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Если хотим беззнаковый тип, добавляем u перед типом. Например, &lt;strong&gt;uint&lt;/strong&gt;. Это тот же int, только он не может быть отрицательным.&lt;/p&gt;
  &lt;p&gt;Перед именем типа можно добавить слово &lt;strong&gt;const,&lt;/strong&gt; тогда созданная переменная станет константной, то есть программа не даст ее изменить. То есть:&lt;/p&gt;
  &lt;pre&gt;const int a = 5;
a = 7;&lt;/pre&gt;
  &lt;p&gt;такой код не скомпилируется, потому что мы пытаемся изменить константу.&lt;/p&gt;
  &lt;p&gt;Мы можем вместо имени типа писать &lt;strong&gt;var&lt;/strong&gt;, тогда компилятор сам определит тип переменной. Этакая помощь программисту.&lt;/p&gt;
  &lt;p&gt;Нельзя делать проверку на равенство, если пользовался дробными числами. Это рандом. Например тут неизвестно, true будет или false:&lt;/p&gt;
  &lt;pre&gt;double a = 5.5 + 4.5;
Console.WriteLine(f == 10)&lt;/pre&gt;
  &lt;p&gt;Лучше делать так:&lt;/p&gt;
  &lt;pre&gt;Console.WriteLine(f &amp;gt; 10 - 0.001 || f &amp;lt; 10 + 0.001);&lt;/pre&gt;
  &lt;p&gt;В языке C# переменная char занимает всегда 2 байта.&lt;/p&gt;
  &lt;h3&gt;Области памяти&lt;/h3&gt;
  &lt;p&gt;Две области памяти – &lt;strong&gt;стек&lt;/strong&gt; и &lt;strong&gt;куча&lt;/strong&gt;. Стек работает по принципу &amp;quot;первый вошел – последний вышел&amp;quot;. Визуализация – стопка книг. Стек может занимать максимум 100 мегабайт. &lt;/p&gt;
  &lt;p&gt;Каждая объявленная переменная по очереди записывается в стек. Но это работает только с простейшими типами. Объекты более сложных типов (например, пользовательских классов) записываются в &lt;strong&gt;кучу&lt;/strong&gt;, а в стек помещается только &lt;strong&gt;указатель&lt;/strong&gt; на этот объект. Создавать объекты таких сложных типов следует вот так:&lt;/p&gt;
  &lt;pre&gt;Type a = new Type();&lt;/pre&gt;
  &lt;p&gt;Рассмотрим код:&lt;/p&gt;
  &lt;pre&gt;MyType a1 = new MyType();
a1.Name = &amp;quot;Egor&amp;quot;;
MyType a2 = a1;
a2.Name = &amp;quot;Alex&amp;quot;;

Console.WriteLine(a1.Name);
Console.WriteLine(a2.Name);&lt;/pre&gt;
  &lt;p&gt;Вывод:&lt;/p&gt;
  &lt;blockquote&gt;Alex&lt;br /&gt;Alex&lt;/blockquote&gt;
  &lt;p&gt;Изменились имена и в &lt;strong&gt;а1&lt;/strong&gt;, и в &lt;strong&gt;а2&lt;/strong&gt;, потому что обе эти переменные – указатели на один и тот же объект, лежащий в куче. &lt;strong&gt;а1 &lt;/strong&gt;и &lt;strong&gt;а2&lt;/strong&gt; это не два отдельных объекта, а условно два имени для одного и того же объекта.&lt;/p&gt;
  &lt;p&gt;Если мы хотим, чтобы созданный указатель ни на что не указывал, объявлять его нужно так:&lt;/p&gt;
  &lt;pre&gt;MyType a = null;&lt;/pre&gt;
  &lt;p&gt;Если мы попробуем сделать так:&lt;/p&gt;
  &lt;pre&gt;a.Name = &amp;quot;Egor&amp;quot;;&lt;/pre&gt;
  &lt;p&gt;то вылетит ошибка, потому что указатель &lt;strong&gt;а&lt;/strong&gt; ни на что не указывает. Он не привязан ни к какому объекту в куче.&lt;/p&gt;
  &lt;h3&gt;Циклы&lt;/h3&gt;
  &lt;pre&gt;int i = 0;
while(i &amp;lt; 5)
{
   Console.WriteLine(i);
   i++;
}&lt;/pre&gt;
  &lt;p&gt;Вывод:&lt;/p&gt;
  &lt;blockquote&gt;0&lt;br /&gt;1&lt;br /&gt;2&lt;br /&gt;3&lt;br /&gt;4&lt;/blockquote&gt;
  &lt;pre&gt;int i = 0;
do
{
   Console.WriteLine(i);
   i++;
}
while (i &amp;lt; 5)&lt;/pre&gt;
  &lt;p&gt;Вывод будет такой же. При использовании do while цикл гарантированно выполнится минимум один раз.&lt;/p&gt;
  &lt;pre&gt;for (int i = 0; i &amp;lt; 5; i++)
{
   Console.WriteLine(i);
}&lt;/pre&gt;
  &lt;p&gt;Вывод будет такой же. В цикле for пишется через точку запятой:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;действие, которое выполнится перед первой итерацией&lt;/li&gt;
    &lt;li&gt;условие выполнения цикла&lt;/li&gt;
    &lt;li&gt;действие, которые выполняется в конце каждой итерации&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Любое поле в for можно оставить пустым. То есть for( ; ; )&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; если в логическом блоке (цикл или условие) только одна строка, то скобочки {} можно не ставить. Лёша рекомендует ставить их в любом случае.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; чтобы сделать цикл бесконечным, нужно вместо условия вписать true. Например while(true).&lt;/p&gt;
  &lt;h3&gt;Условия&lt;/h3&gt;
  &lt;p&gt;С &lt;strong&gt;if else&lt;/strong&gt; всё понятно, описывать не буду.&lt;/p&gt;
  &lt;p&gt;Про &lt;strong&gt;switch case&lt;/strong&gt;. Работает это так:&lt;/p&gt;
  &lt;pre&gt;switch (numberOfDay)
{
   case 1:
      Console.WriteLine(&amp;quot;понедельник&amp;quot;);
      break;
   case 2:
      Console.WriteLine(&amp;quot;вторник&amp;quot;);
      break;
   case 3:
      Console.WriteLine(&amp;quot;среда&amp;quot;);
      break;
   default:
      Console.WriteLine(&amp;quot;не день недели&amp;quot;);
      break;
}&lt;/pre&gt;
  &lt;p&gt;В зависимости от значения переменной numberOfDay выполнится код одного из кейсов. Если переменная будет равна 2, программа выведет &amp;quot;вторник&amp;quot;. В конце каждого кейса обязательно писать break. Блок default выполняется в случае, если мы не попали ни в один из кейсов. В нашем случае например если numberOfDay равна 834, то выведется &amp;quot;не день недели&amp;quot;.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; желательно изучить дома что такое enum. {DONE}&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;01.02&lt;br /&gt;Занятие 3&lt;/h2&gt;
  &lt;p data-align=&quot;center&quot;&gt;&lt;/p&gt;
  &lt;h3&gt;Разбор вопросов по Git&lt;/h3&gt;
  &lt;p&gt;Команды Git которые можно погуглить:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;git checkout &amp;lt;хешкод коммита&amp;gt;&lt;/code&gt; – переключиться на коммит, код которого мы указали.&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;git cherry-pick &amp;lt;хешкод коммита&amp;gt;&lt;/code&gt; – скопировать указанный коммит на токующую ветку.&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;git reset --hard HEAD~1&lt;/code&gt; – поменять HEAD (последний коммит) ветки. Цифра после тильды – на сколько коммитов сдвинуть HEAD влево. Другими словами, сколько последних коммитов удалить.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Кнопка Compare на GitHub помогает посмотреть изменения, сделанные в текущей ветке по сравнению с main. Если всё ок, то можно делать Pull Request. Главное не забыть добавить Алексея (radzevich) в Reviewers. Для того, чтобы иметь право добавлять человека в ревьюеры, нужно сначала добавить его в Collaborators. Когда человек примет приглашение и станет коллаборатором, тогда уже можно будет добавлять его в ревьюеры пул реквеста.&lt;/p&gt;
  &lt;p&gt;Ревьюеры могут комментировать код, вплоть до каждой строки. Когда ревьюер одобряет пул реквест, то напротив ревьюера в меню Reviewers появится галочка. Когда такую галочку от Алексея получаем, можем делать merge.&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;git branch -d&lt;/code&gt; – удаление ветки локально. Прежде чем удалить ветку, надо с нее слезть (пересесть на ветку main). Это делается командой &lt;code&gt;git checkout main&lt;/code&gt;. Если при попытке удаления ветки гит ругается, а вы уверены, что всё норм, то юзаем команду &lt;code&gt;git branch -D&lt;/code&gt;. Буква Д большая. &lt;/p&gt;
  &lt;p&gt;&lt;code&gt;git pull&lt;/code&gt; – подтянуть на комп изменения с гитхаба. Например когда на гитхабе одобрили пул реквест и замержили (объединили) ветки. На гитхабе эти изменения есть, а локальный гит об этом еще не знает. Команда &lt;code&gt;pull &lt;/code&gt;помогает компу узнать об изменениях, сделанных на GitHub.&lt;/p&gt;
  &lt;p&gt;Для каждой новой домашки мы будем создавать отдельную ветку, беря за основу ветку &lt;code&gt;main&lt;/code&gt;. То есть сначала переключаемся в &lt;code&gt;main&lt;/code&gt;, а потом создаем новую ветку.&lt;/p&gt;
  &lt;blockquote&gt;Алексей: если копируете код из интернета, обязательно разберитесь, как он работает. Не копируйте просто так.&lt;/blockquote&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; Пример хорошо сделанной домашки DaysOfWeek.Master – &lt;a href=&quot;https://github.com/sined07/TMS.Net07.Homework/blob/main/TMS.Net07.Homework.DaysOfWeek/TMS.Net07.Homework.DaysOfWeek.Hard/Program.cs&quot; target=&quot;_blank&quot;&gt;Денис Волохович&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;Типы. Повторение&lt;/h3&gt;
  &lt;p&gt;Иногда можно встретить стрёмные типы вроде &lt;code&gt;System.UInt32&lt;/code&gt;. Это то же самое что &lt;code&gt;uint&lt;/code&gt;. И соответственно. Например &lt;code&gt;System.Decimal&lt;/code&gt; = &lt;code&gt;decimal&lt;/code&gt;.&lt;/p&gt;
  &lt;h3&gt;Операторы&lt;/h3&gt;
  &lt;p&gt;Классификация по количеству операндов:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;унарные –&lt;code&gt; x++&lt;/code&gt;, &lt;code&gt;++x&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;бинарные – &lt;code&gt;x + y&lt;/code&gt;, &lt;code&gt;x = y&lt;/code&gt;, &lt;code&gt;x &amp;lt; y&lt;/code&gt;, &lt;code&gt;x += y&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Классификация по назначению:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;арифметические (+, -, ++, +=, *, %, /)&lt;/li&gt;
    &lt;li&gt;логические (!, &amp;amp;, |, ^)&lt;/li&gt;
    &lt;li&gt;сравнения (==, !=, &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=, ?)&lt;/li&gt;
    &lt;li&gt;default &lt;/li&gt;
    &lt;li&gt;nameof &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Различия постфиксных и префиксных унарных операторов (x++ или ++x):&lt;/p&gt;
  &lt;pre&gt;Console.WriteLine(i); //output: 3
Console.WriteLine(i++); //output: 3
Console.WriteLine(i); //output: 4&lt;/pre&gt;
  &lt;pre&gt;Console.WriteLine(i); //output: 3
Console.WriteLine(++i); //output: 4
Console.WriteLine(i); //output: 4&lt;/pre&gt;
  &lt;p&gt;Теперь про оператор деления. Если мы делим целое число на целое число, то дробная часть отбрасывается. &lt;code&gt;13/5 = 6&lt;/code&gt;. Чтобы получить дробное число, надо один из операндов привести к дробному числу. &lt;br /&gt;То есть &lt;code&gt;double(13)/5 = 2.6&lt;/code&gt; или &lt;code&gt;13/5.0 = 2.6&lt;/code&gt;&lt;/p&gt;
  &lt;h3&gt;Приоритет выполнения операций&lt;/h3&gt;
  &lt;ol&gt;
    &lt;li&gt;&lt;code&gt;x++&lt;/code&gt;, &lt;code&gt;x--&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;++x&lt;/code&gt;, &lt;code&gt;--x&lt;/code&gt;, унарные операторы &lt;code&gt;+&lt;/code&gt; и &lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;аддитивные операторы &lt;code&gt;+&lt;/code&gt; и &lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
  &lt;/ol&gt;
  &lt;blockquote&gt;Алексей: лучше использовать круглые скобки, даже если приоритет операций менять не нужно. Так проще разобраться. А еще лучше разбивать сложные вычисления на отдельные строки. Код так будет читабельнее.&lt;/blockquote&gt;
  &lt;p&gt;Важно помнить про ошибки округления.&lt;/p&gt;
  &lt;h3&gt;Логические операторы&lt;/h3&gt;
  &lt;p&gt;&lt;strong&gt;&lt;br /&gt;Логическое отрицание – !&lt;/strong&gt;&lt;/p&gt;
  &lt;pre&gt;!false = true = 1
!true = false = 0&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;Логическое и  –  &amp;amp;&amp;amp;&lt;br /&gt;&lt;/strong&gt;Получаем true только если оба условия true.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Логическое или  –  ||&lt;br /&gt;&lt;/strong&gt;Получаем true если хотя бы одно условие true. Получаем false только если оба false.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Логическое либо  –  ^&lt;br /&gt;&lt;/strong&gt;Получаем true если &lt;u&gt;только одно&lt;/u&gt; true.&lt;/p&gt;
  &lt;p&gt;Логические операторы чаще всего используются в &lt;code&gt;if()&lt;/code&gt; или в условии выполнения циклов, например &lt;code&gt;while()&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Можно использовать и одинарные операторы, типа &amp;amp;, |. Но они в любом случае вычисляют оба операнда. А двойные делают минимальное необходимое количество вычислений. То есть если в&lt;code&gt; if( условие1 &amp;amp;&amp;amp; условие2)&lt;/code&gt; первое условие будет false, то второе даже не будет вычисляться – итогом сразу будет false.&lt;/p&gt;
  &lt;blockquote&gt;Алексей: лучше всегда использовать двойные. Одинарные могут понадобиться при более сложных задачах, например зашифровать что-то. &lt;/blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Тернарный оператор – ?&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;classify = (input &amp;gt;= 0) ? &amp;quot;nonnegative&amp;quot; : &amp;quot;negative&amp;quot;&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Выводит первое значение (nonnegative) если условие верно. Выводит второе (negative) если неверно.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; эти два кода эквивалентны:&lt;/p&gt;
  &lt;pre&gt;bool isOk = true;
if(isOk == true)&lt;/pre&gt;
  &lt;pre&gt;bool isOk = true;
if(isOk)&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;Оператор default&lt;/strong&gt;&lt;/p&gt;
  &lt;pre&gt;int a = default // a = 0
object o = default // o = null&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;Оператор nameof&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Возвращает имя переменной, свойства объекта метода, типа и т.д.&lt;/p&gt;
  &lt;pre&gt;Console.WriteLine(nameof(numbers.Count)); // output: Count&lt;/pre&gt;
  &lt;p&gt;Чаще всего используется для ведения логов.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; Как переименовать переменную/функцию/метод сразу по всему коду? Нажать на нее, затем два раза нажать Ctrl + R, а затем ввести новое имя.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка: &lt;/em&gt;использовать Culture чтобы сделать программу универсальной для разных регионов. Например, у нас принято выводить дату как ДД.ММ.ГГГГ, а в Англии ММ.ДД.ГГГГ.&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;03.02&lt;br /&gt;Занятие 4&lt;/h2&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h3&gt;Массивы&lt;/h3&gt;
  &lt;p&gt;Массив – коллекция переменных одного типа.&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;int[] a = new int[10]; &lt;/code&gt;– массив из десяти переменных типа int. У них нет имени, имя есть только у самого массива. Если мы хотим обратиться к конкретной переменной (например пятой в массиве), то пользуемся индексом – &lt;code&gt;a[4]&lt;/code&gt;. Индексация ячеек начинается с нуля, поэтому у пятого по счету элемента индекс будет 4. У первого элемента индекс 0.&lt;/p&gt;
  &lt;p&gt;Многомерные массивы – массивы, в ячейках которого лежат другие массивы. Таким образом можно реализовать сетку, то есть матрицу (типа шахматное поле). Трехмерный массив задает трехмерное пространство. &lt;/p&gt;
  &lt;p&gt;&lt;code&gt;int[,,] a3 = new int[10, 5, 2];&lt;/code&gt; – создание трехмерного массива, то есть задание трехмерного пространства 10x5x2. Обращение к элементу массива происходит так: &lt;code&gt;a3[7, 2, 1] = 4&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Можно создать не многомерный массив, а реально массив массивов. В этом случае в ячейках внешнего массива могут лежать внутренние массивы &lt;strong&gt;разной длины&lt;/strong&gt;.&lt;/p&gt;
  &lt;pre&gt;int[][] a = new int[3][];
a[0] = new int[10];
a[1] = new int[5];
a[2] = new int[20];&lt;/pre&gt;
  &lt;p&gt;В этом случае обращение к элементу массива выглядит так: &lt;code&gt;a[1][3] = 4&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Важно:&lt;/strong&gt; длина многомерного массива равна произведению количества ячеек внешнего массива на количество ячеек внутреннего. То есть длина массива &lt;code&gt;a[3,2] &lt;/code&gt;равна 6. А длина массива массива &lt;code&gt;a[3][2] &lt;/code&gt;равна 3.&lt;/p&gt;
  &lt;blockquote&gt;Алексей: лучше пользоваться массивами массивов, чем многомерными массивами. На продакшене почти всегда используются массивы массивов.&lt;/blockquote&gt;
  &lt;h3&gt;Строки&lt;/h3&gt;
  &lt;p&gt;Строка это массив из элементов Char. То есть текст. В отличие от массива, ячейки строк являются неизменяемыми. В отличие от C++, в языке C# строка не имеет никаких нулевых символов.&lt;/p&gt;
  &lt;p&gt;Варианты инициализации строки:&lt;/p&gt;
  &lt;pre&gt;string msg = System.String.Empty; //пустая строка

string msg = &amp;quot;Hello World!&amp;quot;;

// два слеша читаются как один слеш, потому что слеш это служебный символ
string msg = &amp;quot;c:\\Program Files\\Microsoft Visual Studio&amp;quot;;

// собачка говорит нам не считывать служебные символы,
// в этом случае можно юзать один слеш
string msg = @&amp;quot;c:\Program Files\Microsoft Visual Studio&amp;quot;;

// константу можно использовать, если строка используется много раз
const string msg = &amp;quot;Error!&amp;quot;; &lt;/pre&gt;
  &lt;p&gt;Строки можно форматировать с помощью &lt;code&gt;string.Format()&lt;/code&gt;. Есть множество параметров, облегчающих жизнь. Записывать не буду :)&lt;/p&gt;
  &lt;p&gt;Вместо &lt;code&gt;string.Format()&lt;/code&gt; можно использовать интерполяцию, то есть ставить перед строкой значок &lt;code&gt;$&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; чтобы изменять строку, не создавая при этом новую, нужно использовать StringBuilder. Об этом часто спрашивают на собесах.&lt;/p&gt;
  &lt;h3&gt;Методы&lt;/h3&gt;
  &lt;p&gt;Код выносится в отдельный метод, если используется много раз в программе. Это делается для избегания дублирования кода.&lt;/p&gt;
  &lt;p&gt;Функция это метод, который что-то возвращает. Процедура это метод, который ничего не возвращает (void). Например:&lt;/p&gt;
  &lt;pre&gt;static void PrintMyName()
{
   Console.WriteLine(&amp;quot;Egor&amp;quot;);
}&lt;/pre&gt;
  &lt;p&gt;Теперь эти две строки будут эквивалентны:&lt;/p&gt;
  &lt;pre&gt;Console.WriteLine(&amp;quot;Egor&amp;quot;);
PrintMyName();&lt;/pre&gt;
  &lt;p&gt;Чтобы выйти из метода используется &lt;code&gt;return&lt;/code&gt;. Даже в методах void можно написать &lt;code&gt;return;&lt;/code&gt; чтобы закончить выполнение метода.&lt;/p&gt;
  &lt;p&gt;Методу можно задать параметры. Например:&lt;/p&gt;
  &lt;pre&gt;static void PrintMyName(string name)
{
   Console.WriteLine(name);
}&lt;/pre&gt;
  &lt;p&gt;Тогда вызов этого метода должен выглядеть так: &lt;code&gt;PrintMyName(&amp;quot;Egor&amp;quot;);&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Можно сделать два метода с одинаковыми именами, но разными параметрами. Тогда при вызове метода компилятор посмотрит на передаваемые параметры и сам решит, какой из методов нужен.&lt;/p&gt;
  &lt;p&gt;Методы должны обязательно отличаться либо именами, либо параметрами. Методы, которые отличаются только телами, делать нельзя.&lt;/p&gt;
  &lt;p&gt;Когда мы передаем переменную в метод в качестве параметра, а затем внутри метода изменяем ее, то изменяется только копия переменной, которая была создана специально для вызванной функции. Когда функция отработает, эта копия уничтожится. И оригинальная переменная останется неизменной. Демонстрация:&lt;/p&gt;
  &lt;pre&gt;static void Main(string[] args)
{
   int a = 3;
   PlusOne(a);
   Console.WriteLine(a);
}
   
static void PlusOne(int a)
{
   a++;
}&lt;/pre&gt;
  &lt;blockquote&gt;Вывод: 3&lt;/blockquote&gt;
  &lt;p&gt;Для функции &lt;code&gt;PlusOne()&lt;/code&gt; создается отдельная копия переменной &lt;code&gt;a&lt;/code&gt;, которая и изменяется. Оригинальная &lt;code&gt;a&lt;/code&gt; не меняется. Чтобы она менялась, сделать нужно было так:&lt;/p&gt;
  &lt;pre&gt;static void Main(string[] args)
{
   int a = 3;
   a = PlusOne(a);
   Console.WriteLine(a);
}
   
static int PlusOne(int a)
{
   a++;
   return a;
}&lt;/pre&gt;
  &lt;blockquote&gt;Вывод: 4&lt;/blockquote&gt;
  &lt;p&gt;Чтобы метод мог вернуть больше чем одно значение, можно использовать &lt;code&gt;out&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Чтобы в методе менять саму переменную, а не ее копию, можно использовать &lt;code&gt;ref&lt;/code&gt;. Но использовать &lt;code&gt;ref &lt;/code&gt;считается плохим тоном.&lt;/p&gt;
  &lt;p&gt;Чтобы задать неограниченное число параметров, можно использовать &lt;code&gt;params&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка: &lt;/em&gt;нельзя инициализировать объект &lt;code&gt;Random()&lt;/code&gt; в цикле, потому что будет выдаваться одно и то же число. Надо инициализировать его до цикла, а в цикле уже просто вызывать метод &lt;code&gt;Next()&lt;/code&gt;.&lt;/p&gt;
  &lt;h3&gt;Рекурсия&lt;/h3&gt;
  &lt;p&gt;Рекурсия – когда метод вызывает сам себя. Рекурсия может быть бесконечной (пока не вызовет переполнение стека за счет того, что создаст слишком много адресов возврата и копий переменных, передаваемых в качестве параметра).&lt;/p&gt;
  &lt;p&gt;То есть нужно обязательно предусмотреть условие выхода из рекурсии. &lt;/p&gt;
  &lt;p&gt;Хорошим тоном считается использовать цикл вместо рекурсий. Если это возможно, лучше делать так.&lt;/p&gt;
  &lt;p&gt;Пример бесконечной рекурсии:&lt;/p&gt;
  &lt;pre&gt;static int Increase(int a) 
{
   a++;
   a = Increase(a);
   return a;
}&lt;/pre&gt;
  &lt;p&gt;Пример конечной рекурсии:&lt;/p&gt;
  &lt;pre&gt;static int IncreaseUntil15(int a)
{
   if (a == 15)
   {
      return a; // will be reached when a will become 15
   }
   a++;
   a = IncreaseOn15(a);
   return a; // will never be reached
}&lt;/pre&gt;
  &lt;p&gt;Тот же код, но с циклом вместо рекурсии:&lt;/p&gt;
  &lt;pre&gt;static int IncreaseUntil15(int a)
{
   while (a != 15)
   {
      a++;
   }
   return a;
}&lt;/pre&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;08.02&lt;br /&gt;Занятие 5&lt;/h2&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h3&gt;Разбор домашки&lt;/h3&gt;
  &lt;p&gt;Неправильно используем имена. В C# есть общепринятые понятия по именованию переменных и методов. Методы, енамы, классы стоит называть с большой буквы, каждое слово тоже с большой буквы – &lt;code&gt;PrintMyName()&lt;/code&gt;. Переменные принято называть с маленькой буквы, каждое новое слово с большой буквы – &lt;code&gt;valueTwentyOne&lt;/code&gt;. Глобально объявленные константные переменные называют с большой буквы – &lt;code&gt;GlobalValue&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Желательно использовать &lt;code&gt;Double.TryParse()&lt;/code&gt; вместо &lt;code&gt;Convert.ToDouble()&lt;/code&gt;, потому что он быстрее работает. Кроме того, нам не приходится ловить исключения. Ловля исключений (try, catch – позже будем проходить) это очень затратная операция, лучше обходиться без нее.&lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Заметка:&lt;/em&gt; на собеседованиях часто просят реализовать последовательность Фибоначчи. Стандартная реализация, которая самая простая, очень неэффективна. Лучше пользоваться реализацией покруче.&lt;/p&gt;
  &lt;h3&gt;Объектно-ориентированное программирование&lt;/h3&gt;
  &lt;p&gt;Класс – это тип объекта. Объект – это экземпляр класса. То есть мы прописываем свойства будущих объектов, создавая класс, а затем создаем объекты этого класса с помощью команды &lt;code&gt;new&lt;/code&gt;.&lt;/p&gt;
  &lt;pre&gt;class Person
{
   // поля и методы класса, то есть его свойства
}

static void Main(string[] args)
{
   StringBuilder str = new StringBuilder();
   // создали объект str типа StringBuilder
   
   Person egor = new Person();
   // создали объект egor типа Person
   
   Person alex = new Person();
   // создали объект alex типа Person
}&lt;/pre&gt;
  &lt;h3&gt;&lt;em&gt;Три главных принципа ООП: наследование, инкапсуляция, полиморфизм.&lt;/em&gt;&lt;/h3&gt;
  &lt;h3&gt;Наследование&lt;/h3&gt;
  &lt;p&gt;Возможность создавать классы на основе других классов, наследуя их свойства и поведение. Например, наследование можно использовать следующим образом: Транспорт-Машина. Класс Машина наследует свойства и поведение класса Транспорт, добавляя свои новые свойства. &lt;/p&gt;
  &lt;p&gt;Множественного наследования в C# &lt;strong&gt;НЕТ!&lt;/strong&gt; То есть нельзя сделать, чтобы класс наследовал свойства двух и более классов. Но вложенное наследование разрешено. Например Транспорт-Машина-Электрокар.&lt;/p&gt;
  &lt;h3&gt;Полиморфизм&lt;/h3&gt;
  &lt;p&gt;Это свойство, позволяющее иметь множество реализаций одного интерфейса. Использование методов базового типа для всех дочерних типов, не создавая множество перегрузок для каждого дочернего класса отдельно.&lt;/p&gt;
  &lt;h3&gt;Инкапсуляция&lt;/h3&gt;
  &lt;p&gt;Скрытие данных и реализации класса. То есть вот есть метод, он работает и работает. Как именно он работает – нас не интересует. Наш объект должен быть как черный ящик: мы не знаем, что лежит внутри, но знаем, как им пользоваться.&lt;/p&gt;
  &lt;h3&gt;Модификаторы доступа&lt;/h3&gt;
  &lt;p&gt;&lt;strong&gt;public&lt;/strong&gt; – доступно из любого места в коде.&lt;br /&gt;&lt;strong&gt;private&lt;/strong&gt; – доступен только из кода в том же классе.&lt;br /&gt;&lt;strong&gt;protected&lt;/strong&gt; – доступен из кода в том же классе или в производных классах.&lt;br /&gt;&lt;strong&gt;internal &lt;/strong&gt;– доступен в пределах одного файла, то есть одного проекта.&lt;br /&gt;protected internal  – очень редко используется, можете погуглить.&lt;br /&gt;private protected – очень редко используется, можете погуглить.&lt;/p&gt;
  &lt;p&gt;Поля класса всегда должны быть private. А чтобы иметь возможность обращаться к этим полям, создаём для каждого поля геттеры и сеттеры – методы Get и Set. В C# они создаются автоматически. Синтаксис: &lt;code&gt;public string Name { get; set; }&lt;/code&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;Подробнее об ООП можно почитать, погуглив что такое SOLID. Это более подробные правила ООП.&lt;/p&gt;
  &lt;p&gt;Хотя ООП и работает медленнее, чем процедурное или функциональное программирование, и занимает больше памяти, оно предоставляет возможности для &lt;strong&gt;безопасного&lt;/strong&gt; расширения программы. Сейчас ООП используется почти везде.&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;10.02&lt;br /&gt;Занятие 6&lt;/h2&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h3&gt;virtual, override, abstract&lt;/h3&gt;
  &lt;p&gt;Не успел ничего написать. Внимательно слушал.&lt;/p&gt;
  &lt;h3&gt;Конструкторы&lt;/h3&gt;
  &lt;pre&gt;Person kevin = new Person(&amp;quot;Kevin&amp;quot;, 40);
// человек с именем Kevin возрастом 40 лет&lt;/pre&gt;
  &lt;h3&gt;Инициализаторы&lt;/h3&gt;
  &lt;pre&gt;Person kevin = new Person(&amp;quot;Kevin&amp;quot;, 40); // человек с именем Kevin возрастом 40 лет
{
   Name = &amp;quot;Egor&amp;quot;;
   Age = 25;
}
// теперь у переменной kevin имя Egor и возраст 25,
// то есть инициализатор отрабатывает после конструктора&lt;/pre&gt;
  &lt;h3&gt;Статические методы, поля, классы&lt;/h3&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;15.02&lt;br /&gt;Занятие 7&lt;/h2&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;pre&gt;var rectangle = shape as Rectangle;
if (shape is Rectangle rectangle)
{
   Console.WriteLine($&amp;quot;This shape is a rectangle&amp;quot;);
}&lt;/pre&gt;
  &lt;h3&gt;Ивент&lt;/h3&gt;
  &lt;p&gt;Как создавать ивент:&lt;/p&gt;
  &lt;pre&gt;public delegate void OnUserCreateShapeDelegate(Shape shape);
public event OnUserCreateShapeDelegate OnUserCreateShape;&lt;/pre&gt;
  &lt;p&gt;На ивенты могут подписываться только методы, которые возвращают void.&lt;/p&gt;
  &lt;h3&gt;Интерфейс&lt;/h3&gt;
  &lt;p&gt;Интерфейс это то же самое что абстрактный класс, только у него ВСЕ методы по умолчанию абстрактные и public, то есть перед именами методов уже не нужно писать &lt;code&gt;public abstract&lt;/code&gt;. Соответственно, ни один из методов интерфейса не может быть реализован. Только реализован в классах-наследниках интерфейса.&lt;/p&gt;
  &lt;p&gt;Наследовать можно от нескольких интерфейсов сразу.&lt;/p&gt;
  &lt;p&gt;Когда мы переопределяем метод интерфейса, слово &lt;code&gt;override&lt;/code&gt; писать не нужно.&lt;/p&gt;
  &lt;p&gt;Интерфейсы называются с буквы &lt;code&gt;I&lt;/code&gt;. Например &lt;code&gt;public interface IShape&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Есть множество базовых стандартных интерфейсов, например &lt;code&gt;ICloneable&lt;/code&gt;. Если мы реализовываем этот интерфейс (грубо говоря наследуемся от интерфейса &lt;code&gt;ICloneable&lt;/code&gt;), то мы обязаны переопределить метод &lt;code&gt;Clone()&lt;/code&gt;, создающий копию текущего объекта.&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2 data-align=&quot;center&quot;&gt;17.02&lt;br /&gt;Занятие 8&lt;/h2&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;Если в классе есть объект типа &lt;code&gt;StreamWriter&lt;/code&gt;, то этот класс обязательно должен реализовать интерфейс &lt;code&gt;IDisposable&lt;/code&gt;. Тогда надо переопределить метод &lt;code&gt;Dispose()&lt;/code&gt;. Это позволяет использовать &lt;code&gt;using&lt;/code&gt; – автоматическое закрытие потока при окончании работы с ним.&lt;/p&gt;
  &lt;h3&gt;Коллекции&lt;/h3&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Коллекция List&lt;/strong&gt; &lt;/p&gt;
  &lt;p&gt;Отличается от массива наличием логики. Можно пользоваться методом &lt;code&gt;Add()&lt;/code&gt;. Этот контейнер автоматически регулирует свой размер.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Коллекция ArrayList&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Одна из первых в C#. Может одновременно хранить объекты любых типов. Содержит много крутых методов.&lt;/p&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/2a/63/2a631ead-2fab-4a1f-80db-3a8160dff209.jpeg&quot; width=&quot;4000&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;&lt;strong&gt;Коллекция List&amp;lt;T&amp;gt; &lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Вскобках мы задаем, объекты какого типа могут храниться в этой коллекции. Методы примерно такие же.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Коллекция Queue&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;Dequeue()&lt;/code&gt; – извлекает и возвращает первый элемент в очереди.&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;Enqueue()&lt;/code&gt; – добавляет элемент в конец очереди.&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;Peek()&lt;/code&gt; – возвращает первый элемент из начала очереди без удаления.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Коллекция Stack&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Первый вошел, последний вышел. Стопка книг.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Dictionary&amp;lt;Tkey, TValue&amp;gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;В качестве индекса может служить не только int, но что угодно. Используется очень часто. Крутой метод &lt;code&gt;TryGetValue()&lt;/code&gt;. &lt;/p&gt;
  &lt;h3&gt;Индексатор&lt;/h3&gt;
  &lt;p&gt;Позволяет сделать наш класс контейнером. Чтобы можно было обращаться по индексу. Однако с &lt;code&gt;foreach&lt;/code&gt; он работать не будет. Чтобы работал, надо реализовать интерфейсы &lt;code&gt;IEnumerable&lt;/code&gt; (метод &lt;code&gt;GetEnumerator&lt;/code&gt;) и &lt;code&gt;IEnumerator&lt;/code&gt; (методы &lt;code&gt;MoveNext&lt;/code&gt;, &lt;code&gt;Current&lt;/code&gt;, &lt;code&gt;Reset&lt;/code&gt;).&lt;/p&gt;

</content></entry></feed>