Type Checking в C#: typeof, GetType или is? Полный разбор

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Type Checking в C#: typeof, GetType или is? Как не запутаться в трёх соснах

Каждый C#-разработчик, рано или поздно, сталкивается с необходимостью проверить тип объекта. Казалось бы, что может быть проще? Но когда перед тобой три варианта — typeof, GetType() и is — глаза разбегаются, а в голове возникает закономерный вопрос: "А какой из них выбрать?".

Эта статья — не просто сухая выдержка из документации. Мы разберём каждый подход на реальных примерах, выявим подводные камни и дадим чёткие рекомендации. После прочтения вы перестанете гадать и будете точно знать, какой инструмент использовать в конкретной ситуации. Поехали!

Зачем вообще проверять типы в C#?

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

  • Работа с интерфейсами и базовыми классами: Вы получаете объект как object или базовый тип, а вам нужно узнать его реальный "характер".
  • Сериализация и десериализация: JSON или XML приходят в виде строки, и нужно восстановить конкретный тип.
  • Рефлексия (Reflection): Когда вы динамически создаёте объекты или вызываете методы, зная только имя типа.
  • Логирование и отладка: Иногда нужно просто вывести в лог, с каким типом вы сейчас работаете.

И вот тут на сцену выходят наши три героя. Давайте познакомимся с каждым поближе.

typeof — статический взгляд в будущее

typeof — это оператор, который возвращает объект System.Type для известного на этапе компиляции типа. Он работает как справочная служба: "Скажи мне имя класса, и я дам тебе всю информацию о нём".

Как это работает:

Type stringType = typeof(string);
Console.WriteLine(stringType.FullName); // Вывод: System.String

Type intType = typeof(int);
Console.WriteLine(intType.FullName); // Вывод: System.Int32

Ключевая особенность: typeof не требует экземпляра объекта. Это статическая операция. Вы говорите компилятору: "У меня есть тип MyClass, дай мне его метаданные".

Когда использовать:

  • Когда вам нужен тип по имени класса, а не по объекту.
  • В атрибутах (например, [AttributeUsage(typeof(MyAttribute))]).
  • В дженериках: typeof(List<>).

Подводный камень: typeof всегда возвращает точный тип, который вы указали в коде. Он не знает о наследовании. Если у вас есть class Dog : Animal { }, то typeof(Animal) никогда не станет typeof(Dog).

GetType() — динамическое расследование

В отличие от typeof, метод GetType() вызывается на экземпляре объекта. Он берёт реальный объект, лежащий в памяти, и говорит: "Ага, вот ты кто на самом деле!".

Пример:

object obj = "Привет, мир!";
Type typeOfObj = obj.GetType();
Console.WriteLine(typeOfObj.FullName); // Вывод: System.String

// А теперь хитрость:
object obj2 = 42;
Type typeOfObj2 = obj2.GetType();
Console.WriteLine(typeOfObj2.FullName); // Вывод: System.Int32

Обратите внимание: переменная obj объявлена как object, но GetType() "видит" сквозь эту обёртку и возвращает System.String. Это и есть динамическое определение типа.

Когда использовать:

  • Когда вам нужно узнать точный тип объекта во время выполнения.
  • Для сравнения типов: obj.GetType() == typeof(MyClass).
  • В методах, которые принимают object и должны вести себя по-разному для разных типов.

Важное предостережение: GetType() никогда не врёт. Он всегда возвращает самый конкретный тип в цепочке наследования. Если у вас Dog : Animal, то dog.GetType() вернёт Dog, а не Animal. Исключение — если сам объект null. Вызов GetType() на null вызовет NullReferenceException.

is — умный и безопасный

Оператор is — это, пожалуй, самый элегантный и безопасный способ проверки типа в современном C#. Он не просто проверяет, является ли объект экземпляром указанного типа, но и может сразу привести его к этому типу.

Классическое использование:

object obj = "Текст";
if (obj is string)
{
    Console.WriteLine("Это строка!");
}

Современный C# (7.0+): pattern matching с is

object obj = "Привет, C#!";
if (obj is string text)
{
    // Переменная 'text' уже доступна и имеет тип string!
    Console.WriteLine($"Длина строки: {text.Length}");
}

// Ещё круче — switch с pattern matching:
object value = 123;
switch (value)
{
    case int i:
        Console.WriteLine($"Целое число: {i}");
        break;
    case string s:
        Console.WriteLine($"Строка: {s}");
        break;
    case null:
        Console.WriteLine("Это null");
        break;
}

Когда использовать:

  • Когда вам нужно не только проверить тип, но и сразу работать с объектом как с этим типом.
  • Для проверки на совместимость с интерфейсом: if (obj is IDisposable).
  • В современных приложениях — это стандарт де-факто. Забудьте про if (obj is string) { var s = (string)obj; }.

Подводный камень: is проверяет не только точное совпадение, но и совместимость по наследованию. Если Dog : Animal, то dog is Animal вернёт true. Это часто то, что нужно, но иногда может сбить с толку, если вам нужно строгое соответствие.

Сравнительная таблица: typeof vs GetType vs is

Чтобы было наглядно, вот сводка:

Критерий typeof GetType() is
Требует экзем

Блоги

Рекомендаций по книгам