Как узнать тип объекта в рантайме в C# при наследовании
Что проверяют
Различаете ли вы две проверки: «объект этого типа или его наследник» и «объект ровно этого типа», и умеете ли пользоваться сопоставлением с образцом. Следом часто спрашивают, почему частые проверки типа считаются запахом кода и что использовать вместо них.
Как отвечать
obj is Dog d: проверка с объявлением переменной (C# 7). Истинно дляDogи любого наследника, дляnullвсегдаfalse. Заменяет старую связкуisплюс приведение;as:obj as Dogпри неудаче вернётnull, а не бросит исключение. Работает только со ссылочными и nullable-типами, после него нужна проверка наnull, поэтому сейчас чаще пишутis;- приведение
(Dog)obj: при неудачеInvalidCastException. Уместно, когда тип гарантирован и ошибка должна быть громкой; GetType(): фактический тип объекта во время выполнения, независимо от типа переменной.obj.GetType() == typeof(Dog)истинно только при точном совпадении, наследник не пройдёт, а наnullбудетNullReferenceException;typeof(Animal).IsAssignableFrom(t): проверка иерархии на уровнеType, когда объекта нет, например при сканировании сборки рефлексией;switchс шаблонами: несколько веток по типу с условиями и шаблонами свойств (C# 8+).
var sound = animal switch
{
Dog { IsPuppy: true } => "тяв",
Dog => "гав",
Cat => "мяу",
null => throw new ArgumentNullException(nameof(animal)),
_ => "?"
};Порядок веток важен: более конкретный шаблон ставят выше, иначе компилятор сообщит, что ветка уже покрыта предыдущей. Хорошо закончить мыслью, что ветвление по типу часто заменяется виртуальным методом: animal.Speak() сам выберет нужную реализацию.
Где спотыкаются
Ждут, что GetType() == typeof(Animal) сработает для наследника, или считают, что is Animal для Dog вернёт false.
Путают тип переменной и тип объекта. Animal a = new Dog(); даёт a.GetType(), равный Dog: статический тип знает компилятор, фактический известен только во время выполнения.
Пишут цепочку if (x is A) ... else if (x is B) там, где нужен полиморфизм. Каждый новый наследник требует правки всех таких мест, и интервьюер это заметит.