Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
这是一个错误。C#中的typeof运算符只能使用类型名称,不能使用对象。
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");
但是,该技术仍然存在主要问题。如果您的变量为null,则对的调用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
!