Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Это ошибка Оператор typeof в C # может принимать только имена типов, но не объекты.
if (obj1.GetType() == typeof(int))
// Some code here
Это будет работать, но, возможно, не так, как вы ожидаете. Для типов значений, как вы показали здесь, это приемлемо, но для ссылочных типов он будет возвращать true, только если тип был точно такого же типа, а не что-то еще в иерархии наследования. Например:
class Animal{}
class Dog : Animal{}
static void Foo(){
object o = new Dog();
if(o.GetType() == typeof(Animal))
Console.WriteLine("o is an animal");
Console.WriteLine("o is something else");
}
Это напечатало бы "o is something else"
, потому что тип o
- Dog
нет Animal
. Вы можете сделать эту работу, однако, если вы используете IsAssignableFrom
метод Type
класса.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
Этот метод все еще оставляет большую проблему, хотя. Если ваша переменная равна нулю, вызов вызывает GetType()
исключение NullReferenceException. Чтобы заставить его работать правильно, вы должны сделать:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
При этом вы получаете эквивалентное поведение is
ключевого слова. Следовательно, если вы хотите именно такое поведение, вам следует использовать is
ключевое слово, которое более читабельно и более эффективно.
if(o is Animal)
Console.WriteLine("o is an animal");
В большинстве случаев, однако, is
ключевое слово все еще не то, что вы действительно хотите, потому что обычно недостаточно просто знать, что объект имеет определенный тип. Обычно вы хотите использовать этот объект как экземпляр этого типа, что также требует его приведения. И поэтому вы можете написать код вроде этого:
if(o is Animal)
((Animal)o).Speak();
Но это заставляет CLR проверять тип объекта до двух раз. Он проверит его один раз, чтобы удовлетворить is
оператора, и, если o
это действительно так Animal
, мы сделаем это снова, чтобы проверить приведение.
Лучше сделать это вместо этого:
Animal a = o as Animal;
if(a != null)
a.Speak();
as
Оператор слепок , который не будет бросать исключение , если это не удается, вместо возвращения null
. Таким образом, CLR проверяет тип объекта только один раз, и после этого нам просто нужно выполнить нулевую проверку, что более эффективно.
Но будьте осторожны: многие люди попадают в ловушку as
. Поскольку он не генерирует исключения, некоторые люди думают о нем как о «безопасном» касте, и они используют его исключительно, избегая регулярных кастований. Это приводит к таким ошибкам:
(o as Animal).Speak();
В этом случае разработчик явно предполагает, что o
это всегда будет Animal
, и пока их предположение верно, все работает отлично. Но если они не правы, то то, что они в конечном итоге здесь, это NullReferenceException
. С обычным броском они получили бы InvalidCastException
вместо этого, который более правильно определил бы проблему.
Иногда эту ошибку бывает трудно найти:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
Это еще один случай, когда разработчик явно ожидает, o
что это будет Animal
каждый раз, но это не очевидно в конструкторе, где используется as
приведение. Это не очевидно, пока вы не дойдете до Interact
метода, где animal
ожидается , что поле будет назначено положительно. В этом случае вы не только получите ложное исключение, но оно не будет выдано до тех пор, пока потенциально не произойдет намного позже, чем произошла фактическая ошибка.
В итоге:
Если вам нужно только знать, относится ли объект к какому-либо типу, используйте is
.
Если вам нужно обработать объект как экземпляр определенного типа, но вы точно не знаете, что объект будет этого типа, используйте as
и проверьте null
.
Если вам нужно обработать объект как экземпляр определенного типа, и объект должен быть этого типа, используйте обычное приведение.
as
!