Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Это ошибка. Оператор typeof в C # может принимать только имена типов, но не объекты.
if (obj1.GetType() == typeof(int))
// Some code here
Это сработает, но, возможно, не так, как вы ожидали. Для типов значений, как вы показали здесь, это приемлемо, но для ссылочных типов оно вернет истину только в том случае, если тип будет точно таким же типом, а не чем-то другим в иерархии наследования. Например:
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
.
Если вам нужно рассматривать объект как экземпляр определенного типа, и объект должен быть этого типа, используйте обычное приведение.
person
P Daddy
schedule
11.06.2009
as
! - person RCIX   schedule 08.10.2009as
на самом деле не проверка типов ... - person jasonh   schedule 08.10.2009as
- это определенно форма проверки типов, каждый бит не меньше, чемis
! Он эффективно используетis
за кулисами и используется повсюду в MSDN, где он улучшает чистоту кода по сравнению сis
. Вместо того, чтобы сначала проверятьis
, вызовas
устанавливает типизированную переменную, готовую к использованию: если она пуста, ответьте соответствующим образом; в противном случае продолжайте. Конечно, кое-что я видел и довольно часто использовал. - person Zaccone   schedule 20.08.2014GetType
, на который вы ссылаетесь, находится вSystem.Reflection.Assembly
- это совершенно другой метод и здесь не имеет значения. - person Kirk Woll   schedule 11.08.2017