Синтаксис C# для новичков: структура программы, имена, ключевые слова, литералы и типы

Синтаксис C# для новичков: структура программы, имена, ключевые слова, литералы и типы Полезное

Синтаксис C# — это правила записи кода, по которым компилятор отличает правильную программу от набора символов: где ставить ; и фигурные скобки, как называть переменные, какие слова зарезервированы и как записывать значения. Синтаксис отвечает на вопрос «как написано», а семантика — на вопрос «что это значит»: строка int n = "5"; синтаксически корректна, но компилятор отклонит ее по смыслу — в int нельзя положить строку.

Ниже — шпаргалка по пяти опорам синтаксиса: структура программы, идентификаторы, ключевые слова, литералы, переменные и типы. Все примеры и тексты ошибок получены прогоном на .NET SDK 10.0.401 (C# 14) 24.09.2026.

Структура программы на C

Минимальная полная программа в классическом виде:

using System;

namespace Syntax.Demo;

class Program
{
    static void Main()
    {
        // Переменная: тип, имя, значение
        string name = "Otus";
        int year = 2026;

        Console.WriteLine($"Привет, {name}! Сейчас {year} год.");
    }
}

Результат в консоли:

Привет, Otus! Сейчас 2026 год.

Что здесь по строкам:

  • using System; — подключает пространство имен, чтобы писать Console, а не System.Console.
  • namespace Syntax.Demo; — пространство имен на весь файл (такая запись появилась в C# 10; старая форма — с фигурными скобками).
  • class Program — код в C# живет внутри типов: классов, структур, записей.
  • static void Main() — точка входа, с нее начинается выполнение. В программе она одна.
  • { } задают блок, каждая инструкция заканчивается ;, // — комментарий до конца строки (многострочный — /* ... */).

С C# 9 точку входа можно не писать явно — это инструкции верхнего уровня (top-level statements). Файл из одной строки — тоже законченная программа:

Console.WriteLine("Привет из top-level statements");

Компилятор сам обернет такой код в класс и Main. Шаблон dotnet new console создает именно этот вариант, поэтому в учебниках встречаются обе формы — это один и тот же язык. Здесь using System; не нужен: в новых проектах включены неявные using (ImplicitUsings).

Как запустить: в .NET 10 одиночный файл выполняется командой dotnet run hello.cs, в более ранних версиях нужен проект (dotnet new console, затем dotnet run).

Идентификаторы: правила имен

Идентификатор — имя переменной, метода, класса или другой сущности. Правила:

  1. Начинается с буквы или _, дальше — буквы, цифры, _.
  2. Буквы — любые Unicode-буквы, кириллица тоже допустима.
  3. Регистр различается: count и Count — разные имена.
  4. Ключевое слово именем быть не может, кроме записи с префиксом @ (@class).
int count = 1;
int Count = 2;          // другая переменная: регистр важен
int _total = count + Count;
string имя = "Анна";    // буквы Unicode допустимы
int @class = 10;        // ключевое слово как имя - только с @
var var = "var - контекстное слово"; // допустимо, но так не пишут

Console.WriteLine(_total);
Console.WriteLine(имя);
Console.WriteLine(@class);
Console.WriteLine(var);
3
Анна
10
var - контекстное слово

Символ @ не входит в имя: это способ сказать компилятору «здесь идентификатор, а не ключевое слово». В шпаргалках встречается «имя начинается с собаки» — это неверно: @ нужен только для конфликта с ключевым словом. Правило «не длиннее 511 символов» — неточный пересказ реального лимита. Длина локальной переменной на практике не ограничена: имя из 513 символов компилируется. Лимит есть у имен, попадающих в метаданные сборки (методы, типы), и считается в байтах UTF-8: имя метода из 1023 латинских букв компилируется, из 1024 — уже CS7013: Name ... exceeds the maximum length allowed in metadata. Кириллическая буква занимает 2 байта, поэтому для кириллического имени метода потолок — 511 символов (на 512 та же ошибка).

Допустимо — не значит принято. Соглашения .NET об именах:

Что называем Стиль Пример
Класс, метод, свойство PascalCase OrderService, GetTotal
Локальная переменная, параметр camelCase orderCount
Приватное поле _camelCase _cache
Интерфейс I + PascalCase IRepository

Кириллицу в именах компилятор принимает, но в командах и open source пишут латиницей.

Ключевые слова: зарезервированные и контекстные

Ключевые слова — слова с особым смыслом для компилятора. В C# их две группы:

Группа Примеры Можно ли назвать так переменную
Зарезервированные int, class, if, return, true, null, static Нет, только @class
Контекстные var, where, async, await, record, value, get, set Да, особый смысл — только в своем контексте

Зарезервированных слов около восьмидесяти, контекстные добавляются с новыми версиями языка: так новые возможности не ломают старый код, где такое слово уже было именем переменной. Пример неверного кода:

int class = 1;

Компилятор выдает каскад ошибок, первая из них:

error CS1001: Identifier expected

Исправление — другое имя (int classNumber = 1;) или, в крайнем случае, @class. Каскад из нескольких ошибок на одну строку — обычное дело: читайте первую, остальные часто исчезают после ее исправления.

Литералы: как записывать значения

Литерал — значение, записанное прямо в коде: 42, "текст", true. Важно различать литерал и константу: литерал — это запись значения, а константа — именованное неизменяемое значение (const int MaxUsers = 100;), которому литерал присваивается.

bool isReady = true;
int million = 1_000_000;      // разделитель разрядов
int hex = 0xFF;               // 255
int bin = 0b1010;             // 10
long big = 9_000_000_000L;
uint positive = 42u;
double pi = 3.14159;
float ratio = 0.5f;
decimal price = 19.99m;
char letter = 'C';
string path = @"C:\temp\new";           // verbatim: \ не экранирует
string escaped = "Строка 1\nСтрока 2";  // \n - перевод строки
string json = """{"lang": "C#"}""";     // raw-строка, C# 11+
string? nothing = null;

Console.WriteLine($"{isReady} {million} {hex} {bin} {big} {positive}");
Console.WriteLine($"{pi} {ratio} {price} {letter}");
Console.WriteLine(path);
Console.WriteLine(escaped);
Console.WriteLine(json);
Console.WriteLine(nothing is null);
True 1000000 255 10 9000000000 42
3.14159 0.5 19.99 C
C:\temp\new
Строка 1
Строка 2
{"lang": "C#"}
True

Вывод дробных чисел зависит от культуры системы: прогон шел с инвариантной культурой, а при ru-RU вторая строка печатает 3,14159 0,5 19,99 C — с запятой. Сводка по видам:

Литерал Пример Тип по умолчанию / суффикс
Логический true, false bool
Целый 42, 0xFF, 0b1010, 1_000 int, если не помещается — uint, long, ulong (var x = 9_000_000_000; — long); L — long, u — uint
Вещественный 3.14, 1e3 double; f — float, m — decimal
Символьный 'C', '\n' char, одинарные кавычки, ровно один символ
Строковый "текст", @"C:\x", """...""" string, двойные кавычки
Пустая ссылка null нет объекта

Частая ошибка — дробное число без суффикса для decimal или float:

decimal price = 19.99;
error CS0664: Literal of type double cannot be implicitly converted to type 'decimal'; use an 'M' suffix to create a literal of this type

Исправление: 19.99m. Для float то же самое с суффиксом f. Вторая ловушка — кавычки: string s = 'abc'; дает CS1012: Too many characters in character literal, потому что в одинарных кавычках допустим один символ.

Переменные и типы

Переменная — именованное место для значения определенного типа. Объявление: тип, имя, по желанию = и начальное значение. Тип после объявления не меняется, C# — язык со статической типизацией.

const int MaxUsers = 100;
int a = 5;
int b = a;      // копия значения
b = 10;
Console.WriteLine($"a = {a}, b = {b}");

int[] first = { 1, 2, 3 };
int[] second = first;   // копия ссылки на тот же массив
second[0] = 99;
Console.WriteLine($"first[0] = {first[0]}");

var total = 3 + 4;      // тип выведен компилятором: int
Console.WriteLine(total.GetType());
int? maybe = null;
Console.WriteLine(maybe ?? -1);
Console.WriteLine(MaxUsers);
a = 5, b = 10
first[0] = 99
System.Int32
-1
100

Пример показывает главное различие типов в C#:

Типы-значения Ссылочные типы
Примеры int, double, bool, char, decimal, struct string, массивы, class, record
При присваивании копируется само значение ссылка на объект
Может быть null только с ?: int? да; в новых проектах компилятор предупреждает, если тип не помечен ?

var — не «тип без типа», а просьба вывести тип из правой части: var total = 3 + 4; — это ровно int. Без начального значения var не работает. string — ссылочный тип, но неизменяемый, поэтому на практике ведет себя как значение.

Локальную переменную нельзя читать до присваивания:

int x;
Console.WriteLine(x);
error CS0165: Use of unassigned local variable 'x'

Исправление: int x = 0;. Еще одна деталь из соседней области — арифметики: 7 / 2 дает 3 (целочисленное деление двух int), а 7 / 2.0 — 3.5.

Где ловится ошибка: синтаксис, типы, выполнение

Не любая ошибка — синтаксическая. Сводка по реальному прогону:

Код Сообщение компилятора / среды Этап
Console.WriteLine("Привет") без ; внутри Main CS1002: ; expected синтаксис
int 2count = 1; CS1001: Identifier expected синтаксис
console.WriteLine("hi"); CS0103: The name 'console' does not exist in the current context семантика (имя не найдено)
int n = "5"; CS0029: Cannot implicitly convert type 'string' to 'int' семантика (типы)
string s = null; Console.WriteLine(s.Length); предупреждения CS8600, CS8602, затем NullReferenceException выполнение

Последняя строка важна: код с предупреждениями компилируется и падает уже при запуске. Предупреждения о null стоит читать как ошибки. Номер ошибки (CS0029) удобно искать в документации Microsoft — там есть описание каждой.

Одна оговорка про ;: в файле с инструкциями верхнего уровня пропуск точки с запятой после объявления (int a = 1, а на следующей строке int b = 2;) дает другое сообщение (CS1003: Syntax error, ',' expected), потому что компилятор пытается прочитать две строки как одно объявление. Смотрите на позицию в скобках (строка,столбец) — она указывает, где парсер споткнулся.

Выводы

  • Программа на C# — это типы (классы) с методами; выполнение начинается с Main или с инструкций верхнего уровня (C# 9+), которые компилятор оборачивает в Main сам.
  • Имя начинается с буквы или _, регистр важен; @ нужен только, чтобы использовать ключевое слово как имя.
  • Зарезервированные слова нельзя брать в имена, контекстные (var, record, await) — можно, но не нужно.
  • У литерала есть тип по умолчанию: дробное число — это double, для decimal и float нужен суффикс m или f.
  • Типы-значения копируют данные, ссылочные — ссылку; синтаксически верный код еще может не пройти проверку типов или упасть при запуске.

Где применяется / связь с практикой

Освойте тему на практике

Эти правила — фундамент любого кода на C#: бэкенда на ASP.NET Core, игр на Unity, десктопных и консольных утилит. Следующий шаг после синтаксиса — управляющие конструкции, методы, классы и коллекции. Если хочется пройти этот путь с практическими заданиями и разбором кода, есть курс «C#-разработчик. Базовый уровень». Попробовать формат можно на бесплатных открытых уроках Otus.

Смежные темы: первые уроки C#, описание и особенности языка C#.

FAQ

Чем синтаксис C# похож на Java и C++?
Фигурные скобки, ; в конце инструкций, объявление «тип имя» и основные операторы унаследованы от C-подобных языков. Отличия начинаются в деталях: свойства, var, ? для null, строки $"..." и """...""".

Обязательно ли писать namespace и класс Program?
Для маленькой программы нет: инструкции верхнего уровня работают с C# 9. В проекте из нескольких файлов пространства имен и классы все равно понадобятся для организации кода.

Где быстро проверить кусок кода без установки Visual Studio?
Достаточно .NET SDK: в .NET 10 файл запускается командой dotnet run имя.cs. Подойдут и VS Code с расширением C# Dev Kit, и JetBrains Rider.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)