<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Egor</title><generator>teletype.in</generator><description><![CDATA[Minsk | Freelance recruiter | BSUIR student | Learning C# .NET]]></description><link>https://teletype.in/@dalival?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dalival</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/dalival?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/dalival?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Wed, 15 Apr 2026 16:16:44 GMT</pubDate><lastBuildDate>Wed, 15 Apr 2026 16:16:44 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@dalival/TMS.Net07</guid><link>https://teletype.in/@dalival/TMS.Net07?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dalival</link><comments>https://teletype.in/@dalival/TMS.Net07?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=dalival#comments</comments><dc:creator>dalival</dc:creator><title>TeachMeSkills C# .NET</title><pubDate>Wed, 27 Jan 2021 18:36:27 GMT</pubDate><description><![CDATA[<img src="https://teletype.in/files/2a/63/2a631ead-2fab-4a1f-80db-3a8160dff209.jpeg"></img>Заметка: заметки никак не связаны с основным конспектом. Можно воспользоваться поиском по слову Заметка, чтобы найти все инсайты.]]></description><content:encoded><![CDATA[
  <p><em>Заметка:</em> заметки никак не связаны с основным конспектом. Можно воспользоваться поиском по слову Заметка, чтобы найти все инсайты.</p>
  <p></p>
  <h2 data-align="center">27.01<br />Занятие 2</h2>
  <p></p>
  <p><em>Заметка:</em> Stepik – сайт с курсами. Проходишь пару уроков, и тебе присылают лицензию на IDE от JetBrains. Она удобнее вижлы. Для C# называется Rider. В него встроен решарпер – автоматическая проверка кода на сложные ошибки.</p>
  <p><em>Заметка:</em><br />Ctrl K C – закомментить код<br />Ctrl K U – раскомментить код<br />Ctrl K F – форматировать код</p>
  <p>Самые ходовые типы:</p>
  <ul>
    <li><strong>int</strong> – целое число. Всегда 4 байта, независимо от архитектуры, в отличие от других языков.</li>
    <li><strong>double</strong> – дробное число, только надо в конце d ставить, например double a = 10.56d. UPD: букву d писать необязательно.</li>
    <li><strong>decimal</strong> – для точных вычислений, например денег. В конце ставить m.</li>
  </ul>
  <p>Если хотим беззнаковый тип, добавляем u перед типом. Например, <strong>uint</strong>. Это тот же int, только он не может быть отрицательным.</p>
  <p>Перед именем типа можно добавить слово <strong>const,</strong> тогда созданная переменная станет константной, то есть программа не даст ее изменить. То есть:</p>
  <pre>const int a = 5;
a = 7;</pre>
  <p>такой код не скомпилируется, потому что мы пытаемся изменить константу.</p>
  <p>Мы можем вместо имени типа писать <strong>var</strong>, тогда компилятор сам определит тип переменной. Этакая помощь программисту.</p>
  <p>Нельзя делать проверку на равенство, если пользовался дробными числами. Это рандом. Например тут неизвестно, true будет или false:</p>
  <pre>double a = 5.5 + 4.5;
Console.WriteLine(f == 10)</pre>
  <p>Лучше делать так:</p>
  <pre>Console.WriteLine(f &gt; 10 - 0.001 || f &lt; 10 + 0.001);</pre>
  <p>В языке C# переменная char занимает всегда 2 байта.</p>
  <h3>Области памяти</h3>
  <p>Две области памяти – <strong>стек</strong> и <strong>куча</strong>. Стек работает по принципу &quot;первый вошел – последний вышел&quot;. Визуализация – стопка книг. Стек может занимать максимум 100 мегабайт. </p>
  <p>Каждая объявленная переменная по очереди записывается в стек. Но это работает только с простейшими типами. Объекты более сложных типов (например, пользовательских классов) записываются в <strong>кучу</strong>, а в стек помещается только <strong>указатель</strong> на этот объект. Создавать объекты таких сложных типов следует вот так:</p>
  <pre>Type a = new Type();</pre>
  <p>Рассмотрим код:</p>
  <pre>MyType a1 = new MyType();
a1.Name = &quot;Egor&quot;;
MyType a2 = a1;
a2.Name = &quot;Alex&quot;;

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

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

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

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

// константу можно использовать, если строка используется много раз
const string msg = &quot;Error!&quot;; </pre>
  <p>Строки можно форматировать с помощью <code>string.Format()</code>. Есть множество параметров, облегчающих жизнь. Записывать не буду :)</p>
  <p>Вместо <code>string.Format()</code> можно использовать интерполяцию, то есть ставить перед строкой значок <code>$</code>.</p>
  <p><em>Заметка:</em> чтобы изменять строку, не создавая при этом новую, нужно использовать StringBuilder. Об этом часто спрашивают на собесах.</p>
  <h3>Методы</h3>
  <p>Код выносится в отдельный метод, если используется много раз в программе. Это делается для избегания дублирования кода.</p>
  <p>Функция это метод, который что-то возвращает. Процедура это метод, который ничего не возвращает (void). Например:</p>
  <pre>static void PrintMyName()
{
   Console.WriteLine(&quot;Egor&quot;);
}</pre>
  <p>Теперь эти две строки будут эквивалентны:</p>
  <pre>Console.WriteLine(&quot;Egor&quot;);
PrintMyName();</pre>
  <p>Чтобы выйти из метода используется <code>return</code>. Даже в методах void можно написать <code>return;</code> чтобы закончить выполнение метода.</p>
  <p>Методу можно задать параметры. Например:</p>
  <pre>static void PrintMyName(string name)
{
   Console.WriteLine(name);
}</pre>
  <p>Тогда вызов этого метода должен выглядеть так: <code>PrintMyName(&quot;Egor&quot;);</code></p>
  <p>Можно сделать два метода с одинаковыми именами, но разными параметрами. Тогда при вызове метода компилятор посмотрит на передаваемые параметры и сам решит, какой из методов нужен.</p>
  <p>Методы должны обязательно отличаться либо именами, либо параметрами. Методы, которые отличаются только телами, делать нельзя.</p>
  <p>Когда мы передаем переменную в метод в качестве параметра, а затем внутри метода изменяем ее, то изменяется только копия переменной, которая была создана специально для вызванной функции. Когда функция отработает, эта копия уничтожится. И оригинальная переменная останется неизменной. Демонстрация:</p>
  <pre>static void Main(string[] args)
{
   int a = 3;
   PlusOne(a);
   Console.WriteLine(a);
}
   
static void PlusOne(int a)
{
   a++;
}</pre>
  <blockquote>Вывод: 3</blockquote>
  <p>Для функции <code>PlusOne()</code> создается отдельная копия переменной <code>a</code>, которая и изменяется. Оригинальная <code>a</code> не меняется. Чтобы она менялась, сделать нужно было так:</p>
  <pre>static void Main(string[] args)
{
   int a = 3;
   a = PlusOne(a);
   Console.WriteLine(a);
}
   
static int PlusOne(int a)
{
   a++;
   return a;
}</pre>
  <blockquote>Вывод: 4</blockquote>
  <p>Чтобы метод мог вернуть больше чем одно значение, можно использовать <code>out</code>.</p>
  <p>Чтобы в методе менять саму переменную, а не ее копию, можно использовать <code>ref</code>. Но использовать <code>ref </code>считается плохим тоном.</p>
  <p>Чтобы задать неограниченное число параметров, можно использовать <code>params</code>.</p>
  <p><em>Заметка: </em>нельзя инициализировать объект <code>Random()</code> в цикле, потому что будет выдаваться одно и то же число. Надо инициализировать его до цикла, а в цикле уже просто вызывать метод <code>Next()</code>.</p>
  <h3>Рекурсия</h3>
  <p>Рекурсия – когда метод вызывает сам себя. Рекурсия может быть бесконечной (пока не вызовет переполнение стека за счет того, что создаст слишком много адресов возврата и копий переменных, передаваемых в качестве параметра).</p>
  <p>То есть нужно обязательно предусмотреть условие выхода из рекурсии. </p>
  <p>Хорошим тоном считается использовать цикл вместо рекурсий. Если это возможно, лучше делать так.</p>
  <p>Пример бесконечной рекурсии:</p>
  <pre>static int Increase(int a) 
{
   a++;
   a = Increase(a);
   return a;
}</pre>
  <p>Пример конечной рекурсии:</p>
  <pre>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
}</pre>
  <p>Тот же код, но с циклом вместо рекурсии:</p>
  <pre>static int IncreaseUntil15(int a)
{
   while (a != 15)
   {
      a++;
   }
   return a;
}</pre>
  <p></p>
  <h2 data-align="center">08.02<br />Занятие 5</h2>
  <p></p>
  <h3>Разбор домашки</h3>
  <p>Неправильно используем имена. В C# есть общепринятые понятия по именованию переменных и методов. Методы, енамы, классы стоит называть с большой буквы, каждое слово тоже с большой буквы – <code>PrintMyName()</code>. Переменные принято называть с маленькой буквы, каждое новое слово с большой буквы – <code>valueTwentyOne</code>. Глобально объявленные константные переменные называют с большой буквы – <code>GlobalValue</code>.</p>
  <p>Желательно использовать <code>Double.TryParse()</code> вместо <code>Convert.ToDouble()</code>, потому что он быстрее работает. Кроме того, нам не приходится ловить исключения. Ловля исключений (try, catch – позже будем проходить) это очень затратная операция, лучше обходиться без нее.</p>
  <p><em>Заметка:</em> на собеседованиях часто просят реализовать последовательность Фибоначчи. Стандартная реализация, которая самая простая, очень неэффективна. Лучше пользоваться реализацией покруче.</p>
  <h3>Объектно-ориентированное программирование</h3>
  <p>Класс – это тип объекта. Объект – это экземпляр класса. То есть мы прописываем свойства будущих объектов, создавая класс, а затем создаем объекты этого класса с помощью команды <code>new</code>.</p>
  <pre>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
}</pre>
  <h3><em>Три главных принципа ООП: наследование, инкапсуляция, полиморфизм.</em></h3>
  <h3>Наследование</h3>
  <p>Возможность создавать классы на основе других классов, наследуя их свойства и поведение. Например, наследование можно использовать следующим образом: Транспорт-Машина. Класс Машина наследует свойства и поведение класса Транспорт, добавляя свои новые свойства. </p>
  <p>Множественного наследования в C# <strong>НЕТ!</strong> То есть нельзя сделать, чтобы класс наследовал свойства двух и более классов. Но вложенное наследование разрешено. Например Транспорт-Машина-Электрокар.</p>
  <h3>Полиморфизм</h3>
  <p>Это свойство, позволяющее иметь множество реализаций одного интерфейса. Использование методов базового типа для всех дочерних типов, не создавая множество перегрузок для каждого дочернего класса отдельно.</p>
  <h3>Инкапсуляция</h3>
  <p>Скрытие данных и реализации класса. То есть вот есть метод, он работает и работает. Как именно он работает – нас не интересует. Наш объект должен быть как черный ящик: мы не знаем, что лежит внутри, но знаем, как им пользоваться.</p>
  <h3>Модификаторы доступа</h3>
  <p><strong>public</strong> – доступно из любого места в коде.<br /><strong>private</strong> – доступен только из кода в том же классе.<br /><strong>protected</strong> – доступен из кода в том же классе или в производных классах.<br /><strong>internal </strong>– доступен в пределах одного файла, то есть одного проекта.<br />protected internal  – очень редко используется, можете погуглить.<br />private protected – очень редко используется, можете погуглить.</p>
  <p>Поля класса всегда должны быть private. А чтобы иметь возможность обращаться к этим полям, создаём для каждого поля геттеры и сеттеры – методы Get и Set. В C# они создаются автоматически. Синтаксис: <code>public string Name { get; set; }</code></p>
  <hr />
  <p>Подробнее об ООП можно почитать, погуглив что такое SOLID. Это более подробные правила ООП.</p>
  <p>Хотя ООП и работает медленнее, чем процедурное или функциональное программирование, и занимает больше памяти, оно предоставляет возможности для <strong>безопасного</strong> расширения программы. Сейчас ООП используется почти везде.</p>
  <p></p>
  <h2 data-align="center">10.02<br />Занятие 6</h2>
  <p></p>
  <h3>virtual, override, abstract</h3>
  <p>Не успел ничего написать. Внимательно слушал.</p>
  <h3>Конструкторы</h3>
  <pre>Person kevin = new Person(&quot;Kevin&quot;, 40);
// человек с именем Kevin возрастом 40 лет</pre>
  <h3>Инициализаторы</h3>
  <pre>Person kevin = new Person(&quot;Kevin&quot;, 40); // человек с именем Kevin возрастом 40 лет
{
   Name = &quot;Egor&quot;;
   Age = 25;
}
// теперь у переменной kevin имя Egor и возраст 25,
// то есть инициализатор отрабатывает после конструктора</pre>
  <h3>Статические методы, поля, классы</h3>
  <p></p>
  <h2 data-align="center">15.02<br />Занятие 7</h2>
  <p></p>
  <pre>var rectangle = shape as Rectangle;
if (shape is Rectangle rectangle)
{
   Console.WriteLine($&quot;This shape is a rectangle&quot;);
}</pre>
  <h3>Ивент</h3>
  <p>Как создавать ивент:</p>
  <pre>public delegate void OnUserCreateShapeDelegate(Shape shape);
public event OnUserCreateShapeDelegate OnUserCreateShape;</pre>
  <p>На ивенты могут подписываться только методы, которые возвращают void.</p>
  <h3>Интерфейс</h3>
  <p>Интерфейс это то же самое что абстрактный класс, только у него ВСЕ методы по умолчанию абстрактные и public, то есть перед именами методов уже не нужно писать <code>public abstract</code>. Соответственно, ни один из методов интерфейса не может быть реализован. Только реализован в классах-наследниках интерфейса.</p>
  <p>Наследовать можно от нескольких интерфейсов сразу.</p>
  <p>Когда мы переопределяем метод интерфейса, слово <code>override</code> писать не нужно.</p>
  <p>Интерфейсы называются с буквы <code>I</code>. Например <code>public interface IShape</code>.</p>
  <p>Есть множество базовых стандартных интерфейсов, например <code>ICloneable</code>. Если мы реализовываем этот интерфейс (грубо говоря наследуемся от интерфейса <code>ICloneable</code>), то мы обязаны переопределить метод <code>Clone()</code>, создающий копию текущего объекта.</p>
  <p></p>
  <h2 data-align="center">17.02<br />Занятие 8</h2>
  <p></p>
  <p>Если в классе есть объект типа <code>StreamWriter</code>, то этот класс обязательно должен реализовать интерфейс <code>IDisposable</code>. Тогда надо переопределить метод <code>Dispose()</code>. Это позволяет использовать <code>using</code> – автоматическое закрытие потока при окончании работы с ним.</p>
  <h3>Коллекции</h3>
  <p></p>
  <p><strong>Коллекция List</strong> </p>
  <p>Отличается от массива наличием логики. Можно пользоваться методом <code>Add()</code>. Этот контейнер автоматически регулирует свой размер.</p>
  <p><strong>Коллекция ArrayList</strong></p>
  <p>Одна из первых в C#. Может одновременно хранить объекты любых типов. Содержит много крутых методов.</p>
  <figure class="m_column">
    <img src="https://teletype.in/files/2a/63/2a631ead-2fab-4a1f-80db-3a8160dff209.jpeg" width="4000" />
  </figure>
  <p><strong>Коллекция List&lt;T&gt; </strong></p>
  <p>Вскобках мы задаем, объекты какого типа могут храниться в этой коллекции. Методы примерно такие же.</p>
  <p><strong>Коллекция Queue&lt;T&gt;</strong></p>
  <p><code>Dequeue()</code> – извлекает и возвращает первый элемент в очереди.</p>
  <p><code>Enqueue()</code> – добавляет элемент в конец очереди.</p>
  <p><code>Peek()</code> – возвращает первый элемент из начала очереди без удаления.</p>
  <p><strong>Коллекция Stack&lt;T&gt;</strong></p>
  <p>Первый вошел, последний вышел. Стопка книг.</p>
  <p><strong>Dictionary&lt;Tkey, TValue&gt;</strong></p>
  <p>В качестве индекса может служить не только int, но что угодно. Используется очень часто. Крутой метод <code>TryGetValue()</code>. </p>
  <h3>Индексатор</h3>
  <p>Позволяет сделать наш класс контейнером. Чтобы можно было обращаться по индексу. Однако с <code>foreach</code> он работать не будет. Чтобы работал, надо реализовать интерфейсы <code>IEnumerable</code> (метод <code>GetEnumerator</code>) и <code>IEnumerator</code> (методы <code>MoveNext</code>, <code>Current</code>, <code>Reset</code>).</p>

]]></content:encoded></item></channel></rss>