Синтаксис 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).
Идентификаторы: правила имен
Идентификатор — имя переменной, метода, класса или другой сущности. Правила:
- Начинается с буквы или
_, дальше — буквы, цифры,_. - Буквы — любые Unicode-буквы, кириллица тоже допустима.
- Регистр различается:
countиCount— разные имена. - Ключевое слово именем быть не может, кроме записи с префиксом
@(@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.



