Type Checking в C#: typeof, GetType() или is? Когда что использовать?
Разбираем три способа проверки типов в C#
Отличный вопрос! Действительно, на первый взгляд эти три конструкции кажутся похожими, но у них совершенно разное назначение. Давайте разберём каждую подробно.
1. Оператор typeof
typeof — это оператор, который возвращает объект System.Type для известного на этапе компиляции типа. Он работает исключительно с именами типов, а не с экземплярами.
Type stringType = typeof(string); // Всегда вернёт System.String
Type intType = typeof(int); // Всегда вернёт System.Int32
// НЕЛЬЗЯ: typeof(obj) — синтаксическая ошибка!
Главное правило: typeof используется, когда вы точно знаете тип на этапе написания кода и вам нужно получить его метаданные (например, для рефлексии или сравнения).
2. Метод GetType()
GetType() — это метод, определённый в базовом классе System.Object. Он возвращает реальный тип объекта во время выполнения. Это критически важно для полиморфизма.
object obj = "Hello";
Console.WriteLine(obj.GetType()); // Выведет: System.String
object num = 42;
Console.WriteLine(num.GetType()); // Выведет: System.Int32
// Классический пример с наследованием
class Animal { }
class Dog : Animal { }
Animal pet = new Dog();
Console.WriteLine(pet.GetType()); // Выведет: Dog, а не Animal!
GetType() всегда показывает фактический тип объекта, а не тип переменной, через которую вы к нему обращаетесь.
3. Оператор is
Оператор is проверяет совместимость типов. Он проверяет, можно ли привести объект к указанному типу (с учётом наследования и интерфейсов).
object obj = "Hello";
if (obj is string) // true — строка совместима с string
Console.WriteLine("Это строка");
if (obj is object) // true — любой тип совместим с object
Console.WriteLine("Это object");
if (obj is int) // false — строку нельзя привести к int
Console.WriteLine("Это int");
// Современный синтаксис (C# 7+): pattern matching
if (obj is string text)
Console.WriteLine($"Длина строки: {text.Length}");
Обратите внимание: is не просто проверяет, но и может сразу присвоить значение в новую переменную (pattern matching).
Когда что использовать?
typeof— когда вам нуженTypeдля известного типа на этапе компиляции. Пример: передача в методы рефлексии, создание экземпляров черезActivator.CreateInstance, сравнение с результатомGetType().GetType()— когда нужно узнать точный тип объекта во время выполнения. Пример: логирование, сериализация, проверка, является ли объект экземпляром конкретного класса (не производного).is— когда нужно проверить совместимость типов (включая наследование и интерфейсы) и/или выполнить безопасное приведение. Это самый частый вариант в обычном коде.
Подводные камни и важные нюансы
- Разница между
isиGetType()при наследовании:class Base { } class Derived : Base { } object obj = new Derived(); Console.WriteLine(obj is Base); // true — Derived совместим с Base Console.WriteLine(obj.GetType() == typeof(Base)); // false — реальный тип Derived - Value types и boxing:
int number = 42; object boxed = number; Console.WriteLine(boxed.GetType() == typeof(int)); // true Console.WriteLine(boxed is int); // true (распаковка) Console.WriteLine(typeof(int) == boxed.GetType()); // true - Производительность:
is— самый быстрый, часто оптимизируется JIT.GetType()+==— медленнее из-за виртуального вызова.typeof— константа времени компиляции, но сравнение сGetType()всё равно включает вызов метода.
Итоговая рекомендация
В 90% случаев вам нужен оператор is — он интуитивно понятен, безопасен и производителен. GetType() используйте только когда вам действительно нужен точный тип (например, для хеширования или сравнения с запретом наследования). typeof — для рефлексии и статических проверок.
Дополнение: когда использовать GetType() вместо is
Коллега выше отлично описал основы. Хочу добавить важный практический пример, где GetType() незаменим, а is может привести к ошибке.
Рассмотрим сценарий с переопределением Equals():
public class Person
{
public string Name { get; set; }
public override bool Equals(object obj)
{
// НЕПРАВИЛЬНО: если класс унаследуют, то объект наследника
// пройдёт проверку is, но это разные типы!
if (obj is Person other)
return Name == other.Name;
return false;
}
}
public class Employee : Person { }
// Теперь:
Person p = new Person { Name = "John" };
Employee e = new Employee { Name = "John" };
Console.WriteLine(p.Equals(e)); // true — хотя это разные типы!
Если логика требует строгого совпадения типов (а не совместимости), нужно использовать GetType():
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
Person other = (Person)obj;
return Name == other.Name;
}
Также GetType() полезен при построении словарей-мультиметодов или в системах плагинов, где нужно точно идентифицировать тип объекта. Запомните простое правило: is — для совместимости, GetType() — для точной идентификации.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги