Шпаргалка по C#

Необходимо явно объявлять все переменные

int a = 2; // целое число
double b = 3.1; // действительное число
String text = "строка текста";

Тип переменной указывать не обязательно, если вы сразу присваиваете значение переменной. Для этого вместо типа можно просто писать var. То есть альтернативно можно писать так:

var a = 2; // целое число
var b = 3.0; // действительное число
var text = "строка текста";

В большинстве случаев достаточно использования var.

Арифметические операции

int a, b, c;
double result;

a = 3;
b = 2;
c = 1;

result = a + b; // в result окажется 5
result = a - b; // в result окажется 1
result = a * b; // в result окажется 6
result = a / b; // деление, так как обе переменные целые, то и результате получаем деление нацело, в result окажется 1
result = (float) a / b; // деление, в result окажется 1.5
result = a % b; // остаток от деления, в result окажется 1

result += 2.5; // увеличить значение result на 2.5
result -= 2.5; // уменшить значение result на 2.5
result *= 2.5; // умножить значение result на 2.5
result /= 2.5; // разделить значение result на 2.5

result++; // инкремент, увеличить значение result на 1
result--; // декремент, уменшить значение result на 1

Операции сравнения

int a = 1, b = 2, c = 3;
bool result; // булева (или логическая) переменная

result = a < b; // в result окажется true
result = b > c; // в result окажется false
result = b >= c; // в result окажется false
result = b <= c; // в result окажется true
result = c == b; // сравнение на равенство (обязательно ДВОЙНОЙ знак равенства), в result окажется false
result = c != b; // сравнение на НЕравенство, в result окажется true

Логические операции

int a = 1, b = 2, c = 3;
bool result;

// конъюнкция, логическое И
result = a < b && b < c; // проверка что число b лежит между a и с, в result окажется true

// дизъюнкция, логическое ИЛИ
result = a < b || c < a; // проверка что число a лежит вне промежутка b и с, в result окажется true

Контроль исполнения через if

Контроль исполнения завязан на логические значения, которые имеют булевы значения true/false

Формально имеет следующий вид:

if (condition)  // условие
{
    // выполнится только если condition ИСТИННО (true)
}

Например:

int a = 1, b = 2, c = 3;
if (a < b) 
{
    Console.WriteLine("a меньше b");
}

Можно добавить блок else на случай если condition окажется ложно

if (condition)  // условие
{
    // выполнится только если condition ИСТИННО (true)
} 
else 
{
    // выполнится только если condition ЛОЖНО (false)
}

Например:

int a = 1, b = 2, c = 3;
if (a > b) 
{
    Console.WriteLine("a больше b");
} 
else 
{
    Console.WriteLine("a не больше b"); // выполнится только этот блок
}

Есть возможность проверять сразу несколько условий, в этом случае выполняется только то условие, которое оказалось первым в последовательности из if инструкций

if (condition_1)  // условие 1
{
    // выполнится только если condition_1 ИСТИННО (true)
} 
else if (condition_2) // условие 2
{
    // выполнится только если condition_1 ЛОЖНО (false), а condition_2 ИСТИННО (true)
}
else
{
    // выполнится только если condition_1 и condition_2 ЛОЖНО (false)
}

Например:

int a = 2, b = 2;
if (a > b) 
{
    Console.WriteLine("a больше b");
} 
else if (a == b) 
{
    Console.WriteLine("a равно b");  // выполнится только этот блок
}
else if (a >= b) 
{
    // хотя это условие формально верно, но выполнятся данный блок не будет,
    // так как проверка на равенство a и b идет раньше
    Console.WriteLine("a не меньше b"); 
}
else 
{
    Console.WriteLine("a меньше b");
}

Контроль исполнения через switch

Позволяет проверять переменную или выражение на равенство некоторому дискретному значению и в зависимости от этого значения выполнять тот или иной блок конструкции switch. Допустим мы хотим проверить по оценке в зачетке будет ли студент получать стипендию. Если оценка 4 или 5 - то стипендия будет, а вот если оценка 2 или 3 то придется сидеть на хлебе с водой. Используя if это можно было бы написать так:

var mark = 5;

if (mark == 2 || mark == 3) 
{
    Console.WriteLine("Стипендии не будет.");
}
else if (mark == 4) 
{
    Console.WriteLine("Ура! Стипендия будет.");
}
else if (mark == 5) 
{
    Console.WriteLine("Гуляем по полной!");
}
else
{
    Console.WriteLine("Неверное значение оценки...");
}

так вот switch предлагает альтернативный подход для записи такого выражения, который будет выглядеть так

var mark = 5;

switch(mark)
{
    case 2:
    case 3:
        Console.WriteLine("Стипендии не будет.");
        break;
    case 4:
        Console.WriteLine("Ура! Стипендия будет.");
        break;
    case 5:
        Console.WriteLine("Гуляем по полной!");
        break;
    default:
        Console.WriteLine("Неверное значение оценки...");
        break;
}

Отдельное внимание стоит обратить на наличие ключевого слова break, которое сигнализирует о том что из конструкции switch надо выйти.

Массивы

Массив это упорядоченный список значений. Массив может быть одномерным, многомерным (например, матрица) или массивом массивов. Количество измерений и длина каждого из измерений задаются, когда создается экземпляр массива. Массивы индексируются от нуля: массив с n элементами индексируется от 0 до n-1.

Пример объявления одномерного массива:
int[] array1D = new int[] { 12, 82, 35, 54 };

Console.WriteLine(array1D[0]); // выводим на экран 12
Console.WriteLine(array1D[1]); // выводим на экран 82
Console.WriteLine(array1D[2]); // выводим на экран 35
Console.WriteLine(array1D[3]); // выводим на экран 54

array1D[1] = 15; // изменили значение элемента массива
Console.WriteLine(array1D[1]); // выводим на экран 15

int result;
result = array1D[0] + array1D[3]; // в result окажется 66

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

int[] array1D = new int[4]; // объявили массив из 4 элементов, массивы целого типа по умолчанию инициализируются нулями

// В этом случае, каждый элемент массива имеет пустое значение (так называемый 0)
Console.WriteLine(array1D[0]); // выводим на экран 0
Console.WriteLine(array1D[1]); // выводим на экран 0
Console.WriteLine(array1D[2]); // выводим на экран 0
Console.WriteLine(array1D[3]); // выводим на экран 0
Пример объявления двумерного массива:
int[,] array2D = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };

Console.WriteLine(array2D[2, 1]); // выводим на экран 6

array2D[2, 1] = 15; // меняем значение элемента
Console.WriteLine(array2D[2, 1]); // выводим на экран 15

аналогично можно инициализировать пустой n-мерный массив:

int[,] array2D = new int[4, 2]; // инициализируем матрицу 4 на 2

Console.WriteLine(array2D[2, 1]); // выводим на экран 0

Списки

Бывают ситуации когда необходимо создать массив количество элементов в котором может меняться, для этих случаев C# предоставляет нам в пользование класс List (то бишь список по-русски). Работа с ним почти ни чем не отличается от работы с массивом, за исключением момента инициализации:

var list = new List<int>(){12, 82, 35, 54};

Console.WriteLine(list[1]); // выводим на экран 82

list[1] = 15; // меняем значение элемента
Console.WriteLine(list[1]); // выводим на экран 15

list.Add(20); // добавляем новый элемент, теперь в списке находится {12, 15, 35, 54, 20}
Console.WriteLine(list[4]); // выводим на экран 20

list.RemoveAt(1); // удаляем элемент на позиции 1, теперь в списке находится {12, 35, 54, 20} 

Циклы

И вот рассмотрев работу с массивами сразу появляется желание найти способ перебрать элементы каким-нибудь более оптимизированным способом. Возьмем пример выше:

int[] array1D = new int[] {12, 82, 35, 54 };

Console.WriteLine(array1D[0]); // выводим на экран 12
Console.WriteLine(array1D[1]); // выводим на экран 82
Console.WriteLine(array1D[2]); // выводим на экран 35
Console.WriteLine(array1D[3]); // выводим на экран 54

Очевидно что писать Console.WriteLine по четыре раза дело неблагородное, мы можем просто создать цикл и запустить функцию Console.WriteLine четыре раза, выглядеть это будет так:

int[] array1D = new int[] {12, 82, 35, 54 };

for (int i = 0; i < 4; i++) // пробегая счетчиком с нуля до 4 (не включительно)
{
    // выводим на экран информацию об i-ом элементе
    Console.WriteLine(array1D[i]);
}

тут мы в явном виде указываем количество итераций в цикле, а что если нам не известно количество элементов в массиве (например, мы со списком работаем) или нам просто лень вспоминать, более грамотно запросить количество элементов у самого массива, делается это так:

int[] array1D = new int[] {12, 82, 35, 54 };

for (int i = 0; i < array1D.Length; i++) // пробегая счетчиком с нуля до количества элементов в массиве (не включительно)
{
    // выводим на экран информацию об i-ом элементе
    Console.WriteLine(array1D[i]);
}

есть еще один способ перебора всех элементов массива, с использованием конструкции foreach, которая просто последовательно позволяет получить доступ к каждому элементу массива, причем использование счетчика i в этом случае не нужно:

int[] array1D = new int[] {12, 82, 35, 54 };

foreach (var element in array1D)
{
    Console.WriteLine(element);
}

Контроль управления в цикле с помощью break и continue

бывают ситуации когда перебор элементов хочется прервать, или например пропустить выполнение итерации в цикле. Для этого существует два ключевых слова break и continue

Допустим, что мы хотим выйти из цикла как только встретим первое нечетное число, сделать это можно следующим образом

int[] array1D = new int[] {12, 82, 35, 54 };

foreach (var element in array1D)
{
    if (element % 2 == 1) // если остаток от деления на 2 равен 1, то число нечетное, а мы переходим внутрь этого if
    {
        break; // выйти из цикла -----.
    }          //                     |
               //                     |
    Console.WriteLine(element); //    |
}                               //    V 

В результат выполнения этого кода, на экран выведется только два значения:

12
82

Альтернативная ситуация, когда мы не хотим выйти из цикла, а просто хотим пропустить какую-нибудь итерацию. Например, мы не хотим выводить на экран нечетные числа. Мы можем сделать это так:

int[] array1D = new int[] {12, 82, 35, 54 };

foreach (var element in array1D) // <---------------------------------------+
{                         //                                                | 
    if (element % 2 == 1) //                                                |
    {                     //                                                |
        continue; // пропускаем итерацию и переходим к следущему элементу --^
    }

    Console.WriteLine(element);
}

В результат выполнения этого кода, на экран выведутся только четные числа:

12
82
54

Конструкции while и do/while

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

Формально конструкция имеет следующий вид:

while(condition) 
{
    // пока condition имеет значение true, выполнение этого блока будет повторятся
}

Допустим мы хотим поиграть с компьютером в угадайку. Мы загадываем число от 0 до 100, помещаем его в переменную, назовем ее number и хотим посчитать сколько попыток потребуется компьютеру чтобы угадать число. Для имитации процесса угадывания, мы воспользуемся генератором случайных чисел:

var random = new Random(); // генератор случайных значений
var ourNumber = 14; // тут число которое мы загадали
var counter = 1; // счетчик попыток угадывания

// пока результат очередного случайного числа не совпадет с нашим числом
while (random.Next(0, 101) != ourNumber) 
{
    counter++; // увеличиваем счетчик
}

Console.WriteLine("Компьютеру потребовалось {0} попыток, чтобы угадать наше число.", counter);
Console.ReadLine(); // чтобы окно консольки не закрывалось сразу

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

Еще есть конструкция do/while, которая отличается от while тем что она гарантирует выполнение цикла хотя бы один раз

do
{
    // пока condition имеет значение true, выполнение этого блока будет повторятся
    // причем даже если condition имеет значение false, этот блок все равно будет выполнен один раз
} 
while (condition) 

Пример выше можно переписать:

var random = new Random();
var ourNumber = 14;
var counter = 0; // так как используем do/while счетчик начинаем с 0

do
{
    counter++;
} while (random.Next(0, 101) != ourNumber);

Console.WriteLine("Компьютеру потребовалось {0} попыток, чтобы угадать наше число.", counter);
Console.ReadLine();

Обработка данных от пользователя

Как правило консольное приложение предполагает наличие некоторых вводных данных от пользователя, для этого использует не раз нами применяемый класс Console.

Простой ввод, преобразование строки в число

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

var number1 = Console.ReadLine();
var number2 = Console.ReadLine();

Console.WriteLine(number1 + number2);
Console.ReadLine();

Ввести какие-нибудь числа и получить совсем не то что ожидали:

Как видно на картинке числа не складываются, а просто происходит объединение их цифр.

Происходит это из-за того, что ввод от пользователя по умолчанию принимается за строковые данные. Поэтому чтобы превратить введенные цифры в числа, придется их сначала преобразовать в целые числа, для этого у типа int есть функция Parse, которая преобразует строковое значение в целое число

var number1 = int.Parse(Console.ReadLine());
var number2 = int.Parse(Console.ReadLine());

Console.WriteLine(number1 + number2);
Console.ReadLine();

теперь все будет работать корректно:

Ввод произвольного количества аргументов

Допустим мы хотим запросить у пользователя n-ое количество чисел, и хотим вывести их сумму, для этого нам пригодится цикл do/while, который как раз позволяет выполнять инструкции в цикле неопределённое количество раз в зависимости от условия. В качестве условия выхода из цикла будет считать ситуацию, когда пользователь не ввел никакого числа (то есть просто нажал enter). Введенные числа мы будем заносить в список. И так у нас получится:

string inputNumber; // сюда будем фиксировать введенную строку
var numbers = new List<int>(); // сюда будем заносить числа

while(true) // цикл бесконечный
{
    inputNumber = Console.ReadLine(); // забираем данные от пользователя
    if (string.IsNullOrEmpty(inputNumber)) // если пользователь ничего не ввел то выходим
    {
        break;
    }
    numbers.Add(int.Parse(inputNumber)); // добавляем число в список
}

int sum = 0;
foreach(var value in numbers)
{
    sum += value;
}

Console.WriteLine("Сумма равна: {0}", sum); // выводим сумму чисел на экран
Console.ReadLine();

получим что-то в этом роде:

Математически функции

Для доступа к математическим функциям, таким как синус, косинус, возведение в степень и другим, используется класс Math, вот пример некоторых наиболее часто используемых функций

Console.WriteLine(Math.Cos(Math.PI)); // косинус пи, выведет -1
Console.WriteLine(Math.Sin(Math.PI / 2)); // синус 90 градусов, выведет 1

Console.WriteLine(Math.Log(100, 10)); // логарифм от 100 по основанию 10, выведет 2
Console.WriteLine(Math.Pow(10, 5)); // возведение 10 в степень 5, выведет 100000
Console.WriteLine(Math.Sqrt(144)); // корень квадратный из 144, выведет 12
Console.WriteLine(Math.Abs(-15)); // модуль от -15, выдаст 15

обратите внимание на Math.PI которая является не функцией, а константой, содержащей значение числа \(\pi\)