Разбираем базовый уровень C#
C# — это язык, который поражает своей элегантностью и лаконичностью, но при этом способен решать задачи любого уровня сложности. В мире разработки платформы .NET он стоит особняком: строгая типизация, современный синтаксис и богатая экосистема делают C# истинным профессионалом среди языков. Как и в любом серьёзном деле, прежде чем погрузиться в проект, разработчики часто задаются вопросами: какой механизм здесь применить, какие возможности у типизации, как работает полиморфизм, какие тонкости в работе с файлами?
Чтобы разобраться со всем этим, мы можем использовать практику тестирования: от самых базовых знаний по типам данных до нюансов, связанных с LINQ, наследованием, инкапсуляцией и файловыми операциями. И именно такой тест, где последовательно проверяются ключевые аспекты языка, мы рассмотрим в этом разборе.
Вопрос 1. Сколько байтов занимает тип char в C#?
Обоснование:
В C# тип char представляет собой символ в кодировке UTF-16, который занимает 2 байта (16 бит) в памяти. В отличие от C++, где char может занимать 1 байт, в C# каждый символ представлен в формате System.Char, использующем 16-битное представление.
Вопрос 2. Что выведет следующая программа?
Обоснование:
В C# локальные переменные (переменные, объявленные внутри метода) не инициализируются автоматически. Переменная i объявлена, но не была присвоена никакого значения перед использованием в Console.WriteLine(i);. В отличие от переменных-членов класса, которые инициализируются значением по умолчанию (например, 0 для int), локальные переменные должны быть инициализированы перед использованием, иначе произойдет ошибка компиляции.
Правильный ответ:
✔ Ошибка компиляции (Compile-time error)
Вопрос 3. Укажите результат работы фрагмента программы:
Обоснование:
Разберём пошагово выполнение кода:
- a = 'b'; → a = 'b'
- b = 'c'; → b = 'c'
- c = a; → c = 'b' (так как a = 'b')
- b = c; → b = 'b' (теперь b перезаписывается значением c, а c было 'b')
Теперь вызов Console.WriteLine("{0}{1}{2}{3}{4}", a, b, c, 'c', b); подставляет текущие значения переменных:
В результате программа выведет: "bbbcb"
Вопрос 4. Какое ключевое слово следует применить для запрета наследования от определенного класса?
Обоснование:
В C# для запрета наследования от класса используется ключевое слово sealed. Оно предотвращает создание производных классов, тем самым ограничивая возможность расширения класса.
- Static – делает класс статическим, но не запрещает наследование (статические классы сами по себе не могут быть унаследованы).
- Abstract – наоборот, требует, чтобы класс был унаследован, но не запрещает наследование.
- Internal – ограничивает доступ к классу внутри одной сборки, но не запрещает наследование.
- Const – используется для объявления констант, не применяется к классам.
Вопрос 5. Что такое полиморфизм в C#?
- Процесс, который ограничивает доступ к некоторым компонентам объекта
- Процесс объединения данных и функций в единый компонент
- Возможность класса скрывать его внутренние данные и защищать их от несанкционированных изменений
- Механизм, который позволяет объектам вести себя как объекты другого типа
- Концепция, позволяющая объектам разных типов обрабатываться одинаково через общий интерфейс
Обоснование:
Полиморфизм – это один из основных принципов объектно-ориентированного программирования, который позволяет объектам разных типов обрабатываться одинаково через общий интерфейс или базовый класс. Это означает, что метод может иметь разное поведение в зависимости от типа объекта, который его вызывает.
В C# полиморфизм реализуется через:
- Перегрузку методов (Method Overloading) – несколько методов с одним именем, но разными параметрами.
- Переопределение методов (Method Overriding) – производный класс переопределяет методы базового класса.
- Интерфейсы (Interfaces) – реализация нескольких типов через общий интерфейс.
- Ограничение доступа к компонентам объекта – это инкапсуляция.
- Объединение данных и функций – это абстракция.
- Сокрытие внутренних данных и защита от изменений – это также инкапсуляция.
- Объекты ведут себя как объекты другого типа – это скорее наследование и приведение типов, но не полиморфизм.
Правильный ответ:
✔ Концепция, позволяющая объектам разных типов обрабатываться одинаково через общий интерфейс
Вопрос 6. Имеется два класса и следующий код. Что происходит при вызове a.Write()?
class A
{
public string InformationalString { get; set; }
public A(string info) => InformationalString = info;
public virtual void Write() => Console.WriteLine(InformationalString);
}
class B : A
{
public string AdditionalInformationalString { get; set; }
public B(string info, string additionalInfo): base(info) => AdditionalInformationalString = additionalInfo;
public override void Write() => Console.WriteLine(quot;{InformationalString} has some {AdditionalInformationalString}");
}
A a = new B("object", "properties");
a.Write();
2. Класс B (наследуется от A) содержит:
Console.WriteLine(quot;{InformationalString} has some {AdditionalInformationalString}");
A a = new B("object", "properties");
Здесь a объявлен как объект типа A, но он фактически является экземпляром B (используется полиморфизм).
- Поскольку метод Write() является виртуальным (virtual) в A и переопределён (override) в B, то даже если переменная a имеет тип A, будет вызван метод из B.
- Следовательно, выведется
Выбор правильного ответа:
✔ Выполняется реализация метода Write из класса B, несмотря на то что переменная a — переменная типа A
Вопрос 7. Какой интерфейс должен реализовать класс, чтобы обеспечить выполнение запросов с использованием LINQ?
- ILinq или IQueryable
- IEnumerable или IQueryable
- IEnumerable или ILinq
- IEnumerator или IQueryable
- IEnumerator или ILinq
Обоснование:
LINQ (Language Integrated Query) выполняет запросы к коллекциям данных, и для этого используются два ключевых интерфейса:
- IEnumerable<T> – используется для работы с коллекциями данных в памяти. Запросы LINQ выполняются лениво (lazy evaluation), перебирая элементы с помощью foreach.
- IQueryable<T> – используется для работы с удалёнными источниками данных (например, базы данных через Entity Framework). Этот интерфейс позволяет строить запросы, которые затем транслируются в SQL.
- ILinq – такого интерфейса в C# не существует.
- IEnumerator – используется для перебора элементов в коллекции, но не поддерживает выполнение LINQ-запросов.
- ILinq – не является стандартным интерфейсом в .NET.
Правильный ответ:
✔ IEnumerable или IQueryable
Вопрос 8. У вас есть следующий список:
Вам необходимо получить все числа больше 65. Какой вариант для этого подходит?
- var result = items.Take(65);
- var result = items.Find(i => i > 65);
- var result = items.Select(i => i > 65);
- var result = items.Where(i => i > 65).Select(i);
- var result = items.Any(i => i > 65);
- Take(65) – Этот метод берет первые 65 элементов из списка, но не фильтрует их. Ошибка в логике. ❌
- Find(i => i > 65) – Метод Find() возвращает только первый элемент, который удовлетворяет условию, а нам нужен список. ❌
- Select(i => i > 65) – Метод Select() проецирует (преобразует) каждый элемент, но не фильтрует. В данном случае он вернёт List<bool>. ❌
- Where(i => i > 65).Select(i) – Здесь ошибка синтаксиса: .Select(i) требует указания, что именно нужно выбрать. Однако если исправить на .Select(i => i), то это будет правильный ответ. ✅
- Any(i => i > 65) – Метод Any() возвращает true или false, если есть хотя бы один элемент, подходящий под условие, но не список чисел. ❌
✔ var result = items.Where(i => i > 65).Select(i => i); (с исправленным .Select(i => i))
Вопрос 9. Какой класс необходимо использовать на месте пропуска в коде ниже, чтобы получить список файлов, упорядоченный по времени создания?
- Что делает код?
- Создаёт объект некоторого класса, работающего с файловой системой.
- Получает все файлы в текущем каталоге с помощью .GetFiles("*").
- Сортирует файлы по времени их создания (CreationTime).
- Преобразует результат в список .ToList().
- Какой класс подходит?
- Path – Это статический класс, предназначенный для работы с путями, он не предоставляет метода .GetFiles(). ❌
- Directory – Это статический класс, он не создаёт объекты, а работает с каталогами через статические методы. ❌
- File – Используется для работы с файлами, но не предоставляет .GetFiles() и не создаёт объекты. ❌
- FileInfo – Предоставляет информацию о конкретном файле, но не используется для работы со списками файлов. ❌
- DirectoryInfo – Этот класс представляет каталог, и у него есть метод .GetFiles(), возвращающий массив FileInfo. ✅
Вывод:
✔ DirectoryInfo – правильный ответ, так как этот класс позволяет получить список файлов в каталоге и упорядочить их по CreationTime.
Вопрос 10. Что делает следующий код?
- Открывает файл на запись и чтение. Если файл существует, дописывает в него
- Создаёт новый файл и записывает в него текст. Если файл существует, перезаписывает его
- Создаёт новый файл и записывает в него текст. Если файл существует, вызывает исключение
- Создаёт новый файл и записывает в него текст. Если файл существует, то дописывает в него
- Открывает файл на запись и чтение. Если файл существует, перезаписывает его
Метод File.WriteAllText(path, content) в C# выполняет следующие действия:
- Если файл не существует, создаёт его.
- Если файл уже существует, перезаписывает его (удаляет старое содержимое).
- Записывает переданный текст в файл.
- Не дописывает текст в уже существующий файл (в отличие от File.AppendAllText).
- Не вызывает исключение, если файл существует.
✔ "Создаёт новый файл и записывает в него текст. Если файл существует, перезаписывает его"
Заключение
В языке C# всё сконструировано так, чтобы помочь разработчику оставаться эффективным и создавать надёжные решения. От разветвлённой системы типов до продвинутых возможностей LINQ — каждая деталь работает синхронно. Постепенное углубление в механику языка через подобные тесты не только проверяет наши знания, но и развивает навыки реальной разработки: будь то умение грамотно переопределять методы или уверенно управлять файлами.
Всё, что мы обсудили в тесте, отражает базовые принципы C#, но главное — это лишь часть обширного мира .NET. Если вы хотите почувствовать всю мощь экосистемы, идите дальше, пробуйте свои силы в проектах, исследуйте новые библиотеки и подходы. Но базис, который мы сегодня закрепили, даст вам достаточно прочный фундамент, чтобы двигаться вперёд и создавать по-настоящему первоклассный код