首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型检查: typeof、GetType还是is?

类型检查: typeof、GetType还是is?
EN

Stack Overflow用户
提问于 2009-06-11 19:10:29
回答 12查看 1.2M关注 0票数 1.7K

我见过很多人使用以下代码:

代码语言:javascript
复制
Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

但我知道你也可以这样做:

代码语言:javascript
复制
if (obj1.GetType() == typeof(int))
    // Some code here

或者这样:

代码语言:javascript
复制
if (obj1 is int)
    // Some code here

就我个人而言,我觉得最后一个是最干净的,但我是不是遗漏了什么?哪一个是最好的,还是个人喜好?

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2009-06-11 19:15:50

所有这些都是不同的。

  • typeof接受类型名(在编译时指定) time).
  • GetType获取instance.
  • is的运行时类型,如果实例在继承树中,则返回true。

示例

代码语言:javascript
复制
class Animal { } 
class Dog : Animal { }

void PrintTypes(Animal a) { 
    Console.WriteLine(a.GetType() == typeof(Animal)); // false 
    Console.WriteLine(a is Animal);                   // true 
    Console.WriteLine(a.GetType() == typeof(Dog));    // true
    Console.WriteLine(a is Dog);                      // true 
}

Dog spot = new Dog(); 
PrintTypes(spot);

typeof(T)呢?它也是在编译时解析的吗?

是。T始终是表达式的类型。请记住,泛型方法基本上是具有适当类型的一大堆方法。示例:

代码语言:javascript
复制
string Foo<T>(T parameter) { return typeof(T).Name; }

Animal probably_a_dog = new Dog();
Dog    definitely_a_dog = new Dog();

Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.

Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal". 
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
票数 2.1K
EN

Stack Overflow用户

发布于 2009-06-11 19:17:26

1.

代码语言:javascript
复制
Type t = typeof(obj1);
if (t == typeof(int))

这是非法的,因为typeof只适用于类型,而不适用于变量。我假设obj1是一个变量。因此,通过这种方式,typeof是静态的,并且在编译时而不是运行时执行其工作。

2.

代码语言:javascript
复制
if (obj1.GetType() == typeof(int))

如果obj1恰好是int类型,则为true。如果obj1派生自int,则If条件将为false

3.

代码语言:javascript
复制
if (obj1 is int)

如果obj1是一个int,或者如果它派生自一个名为int的类,或者如果它实现了一个名为int的接口,那么它就是true

票数 87
EN

Stack Overflow用户

发布于 2009-06-11 19:34:01

代码语言:javascript
复制
Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

这是一个错误。C#中的typeof运算符只能接受类型名称,而不能接受对象。

代码语言:javascript
复制
if (obj1.GetType() == typeof(int))
    // Some code here

这将会起作用,但可能不会像您预期的那样。对于值类型,如这里所示,它是可接受的,但对于引用类型,只有当类型是完全相同的类型时,它才会返回true,而不是继承层次结构中的其他类型。例如:

代码语言:javascript
复制
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。但是,如果使用Type类的IsAssignableFrom方法,则可以做到这一点。

代码语言:javascript
复制
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
    Console.WriteLine("o is an animal");

然而,这种技术仍然留下了一个主要问题。如果您的变量为空,则对GetType()的调用将抛出NullReferenceException。所以要让它正常工作,你需要这样做:

代码语言:javascript
复制
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
    Console.WriteLine("o is an animal");

这样,您就拥有了与is关键字相同的行为。因此,如果这是您想要的行为,则应该使用is关键字,该关键字更具可读性,也更高效。

代码语言:javascript
复制
if(o is Animal)
    Console.WriteLine("o is an animal");

然而,在大多数情况下,is关键字仍然不是您真正想要的,因为仅仅知道一个对象是某种类型通常是不够的。通常,您希望将该对象实际用作该类型的实例,这也需要对其进行强制转换。因此,您可能会发现自己编写的代码如下:

代码语言:javascript
复制
if(o is Animal)
    ((Animal)o).Speak();

但这使得CLR最多检查对象的类型两次。它将检查它一次以满足is操作符,如果o确实是一个Animal,我们让它再次检查以验证强制转换。

这样做效率更高:

代码语言:javascript
复制
Animal a = o as Animal;
if(a != null)
    a.Speak();

as运算符是一个强制转换,它不会在失败时抛出异常,而是返回null。这样,CLR只会检查对象的类型一次,之后,我们只需要执行null检查,这会更有效。

但要当心:很多人都会掉进as的陷阱。因为它不抛出异常,所以一些人认为它是一个“安全”的强制转换,并且他们专门使用它,避免常规的强制转换。这会导致如下错误:

代码语言:javascript
复制
(o as Animal).Speak();

在这种情况下,开发人员显然假设o将始终是一个Animal,只要他们的假设是正确的,一切都会正常工作。但是如果他们错了,那么他们最终得到的就是一个NullReferenceException。使用常规的演员阵容,他们会得到一个InvalidCastException,这会更准确地发现问题。

有时,这个bug很难找到:

代码语言:javascript
复制
class Foo{
    readonly Animal animal;

    public Foo(object o){
        animal = o as Animal;
    }

    public void Interact(){
        animal.Speak();
    }
}

这是开发人员每次都明确希望oAnimal的另一种情况,但这在使用as强制转换的构造函数中并不明显。在使用Interact方法之前,这一点并不明显,在该方法中,animal字段应该是正赋值的。在这种情况下,您不仅会得到一个误导性的异常,而且直到可能比实际错误发生时晚得多的时候才会抛出异常。

总而言之:

  • 如果您只需要知道对象是否属于某种类型,请使用null.
  • If如果您需要将对象视为某种类型的实例,但您不确定该对象是否属于该类型,请使用as并检查
    • 您需要将对象视为某种类型的实例,并且该对象应属于该类型,请使用常规强制转换。
票数 57
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/983030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档