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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/983030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:52:37  来源:igfitidea点击:

Type Checking: typeof, GetType, or is?

c#typestypeofgettype

提问by jasonh

I've seen many people use the following code:

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

Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

But I know you could also do this:

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

if (obj1.GetType() == typeof(int))
    // Some code here

Or this:

或这个:

if (obj1 is int)
    // Some code here

Personally, I feel the last one is the cleanest, but is there something I'm missing? Which one is the best to use, or is it personal preference?

就我个人而言,我觉得最后一个是最干净的,但是有什么我遗漏的地方吗?哪个最好用,还是个人喜好?

采纳答案by Jimmy

All are different.

都是不同的。

  • typeoftakes a type name (which you specify at compile time).
  • GetTypegets the runtime type of an instance.
  • isreturns true if an instance is in the inheritance tree.
  • typeof采用类型名称(您在编译时指定)。
  • GetType获取实例的运行时类型。
  • is如果实例在继承树中,则返回 true。

Example

例子

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);


What about typeof(T)? Is it also resolved at compile time?

怎么样typeof(T)?它是否也在编译时解决?

Yes. T is always what the type of the expression is. Remember, a generic method is basically a whole bunch of methods with the appropriate type. Example:

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

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"

回答by StriplingWarrior

I believe the last one also looks at inheritance (e.g. Dog is Animal == true), which is better in most cases.

我相信最后一个也着眼于继承(例如 Dog is Animal == true),在大多数情况下更好。

回答by AllenG

It depends on what I'm doing. If I need a bool value (say, to determine if I'll cast to an int), I'll use is. If I actually need the type for some reason (say, to pass to some other method) I'll use GetType().

这取决于我在做什么。如果我需要一个 bool 值(例如,确定我是否将转换为 int),我将使用is. 如果我出于某种原因确实需要该类型(例如,传递给其他方法),我将使用GetType().

回答by Andrew Hare

Use typeofwhen you want to get the type at compilation time. Use GetTypewhen you want to get the type at execution time. There are rarely any cases to use isas it does a cast and, in most cases, you end up casting the variable anyway.

使用typeof时,你想获得的类型编译时间。使用GetType时,你想要得到的类型执行时间。很少有任何情况可以is像转换一样使用,并且在大多数情况下,您最终还是会转换变量。

There is a fourth option that you haven't considered (especially if you are going to cast an object to the type you find as well); that is to use as.

还有第四个选项你没有考虑过(特别是如果你打算将一个对象强制转换为你找到的类型);即使用as.

Foo foo = obj as Foo;

if (foo != null)
    // your code here

This only uses onecast whereas this approach:

这仅使用一个演员表而这种方法:

if (obj is Foo)
    Foo foo = (Foo)obj;
if (obj is Foo)
    Foo foo = (Foo)obj;

requires two.

需要两个

Update (Jan 2020):

更新(2020 年 1 月):

  • As of C# 7+, you can now cast inline, so the 'is' approach can now be done in one cast as well.
  • 从 C# 7+ 开始,您现在可以内联转换,因此现在也可以在一次转换中完成“是”方法。

Example:

例子:

if(obj is Foo newLocalFoo)
{
    // For example, you can now reference 'newLocalFoo' in this local scope
    Console.WriteLine(newLocalFoo);
}

回答by bobobobo

I prefer is

我更喜欢的

That said, if you're using is, you're likely notusing inheritance properly.

也就是说,如果您使用的是 is,则您可能没有正确使用继承。

Assume that Person : Entity, and that Animal : Entity. Feed is a virtual method in Entity (to make Neil happy)

假设 Person : Entity 和 Animal : Entity。Feed 是 Entity 中的虚方法(为了让 Neil 开心)

class Person
{
  // A Person should be able to Feed
  // another Entity, but they way he feeds
  // each is different
  public override void Feed( Entity e )
  {
    if( e is Person )
    {
      // feed me
    }
    else if( e is Animal )
    {
      // ruff
    }
  }
}

Rather

相当

class Person
{
  public override void Feed( Person p )
  {
    // feed the person
  }
  public override void Feed( Animal a )
  {
    // feed the animal
  }
}

回答by thecoop

The last one is cleaner, more obvious, and also checks for subtypes. The others do not check for polymorphism.

最后一个更干净,更明显,并且还检查子类型。其他的不检查多态性。

回答by Scott Langham

1.

1.

Type t = typeof(obj1);
if (t == typeof(int))

This is illegal, because typeofonly works on types, not on variables. I assume obj1 is a variable. So, in this way typeofis static, and does its work at compile time instead of runtime.

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

2.

2.

if (obj1.GetType() == typeof(int))

This is trueif obj1is exactly of type int. If obj1derives from int, the if condition will be false.

这就是trueifobj1类型int。如果obj1派生自int,则 if 条件将为false

3.

3.

if (obj1 is int)

This is trueif obj1is an int, or if it derives from a class called int, or if it implements an interface called int.

这是trueifobj1是一个int,或者它是否从一个被调用的类派生int,或者它是否实现了一个被调用的接口int

回答by P Daddy

Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

This is an error. The typeof operator in C# can only take type names, not objects.

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

if (obj1.GetType() == typeof(int))
    // Some code here

This will work, but maybe not as you would expect. For value types, as you've shown here, it's acceptable, but for reference types, it would only return true if the type was the exact sametype, not something else in the inheritance hierarchy. For instance:

这会起作用,但可能不像您期望的那样。对于值类型,正如您在此处显示的那样,它是可以接受的,但对于引用类型,如果类型是完全相同的类型,它只会返回 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");
}

This would print "o is something else", because the type of ois Dog, not Animal. You can make this work, however, if you use the IsAssignableFrommethod of the Typeclass.

这将打印"o is something else",因为类型ois Dog, not Animal。但是,如果您使用类的IsAssignableFrom方法,则可以使这项工作起作用Type

if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
    Console.WriteLine("o is an animal");

This technique still leaves a major problem, though. If your variable is null, the call to GetType()will throw a NullReferenceException. So to make it work correctly, you'd do:

不过,这种技术仍然存在一个主要问题。如果您的变量为空,则调用GetType()将抛出 NullReferenceException。因此,要使其正常工作,您需要执行以下操作:

if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
    Console.WriteLine("o is an animal");

With this, you have equivalent behavior of the iskeyword. Hence, if this is the behavior you want, you should use the iskeyword, which is more readable and more efficient.

有了这个,你就有了is关键字的等效行为。因此,如果这是您想要的行为,您应该使用is关键字,它更具可读性和效率。

if(o is Animal)
    Console.WriteLine("o is an animal");

In most cases, though, the iskeyword still isn't what you really want, because it's usually not enough just to know that an object is of a certain type. Usually, you want to actually usethat object as an instance of that type, which requires casting it too. And so you may find yourself writing code like this:

但是,在大多数情况下,is关键字仍然不是您真正想要的,因为通常仅仅知道对象是某种类型是不够的。通常情况下,要真正地使用该对象作为类型,这需要铸造太的一个实例。所以你可能会发现自己在写这样的代码:

if(o is Animal)
    ((Animal)o).Speak();

But that makes the CLR check the object's type up to two times. It will check it once to satisfy the isoperator, and if ois indeed an Animal, we make it check again to validate the cast.

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

It's more efficient to do this instead:

这样做更有效:

Animal a = o as Animal;
if(a != null)
    a.Speak();

The asoperator is a cast that won't throw an exception if it fails, instead returning null. This way, the CLR checks the object's type just once, and after that, we just need to do a null check, which is more efficient.

as操作是,如果它失败了,而不是返回,不会抛出异常铸造null。这样,CLR 只检查一次对象的类型,之后我们只需要做一次空检查,效率更高。

But beware: many people fall into a trap with as. Because it doesn't throw exceptions, some people think of it as a "safe" cast, and they use it exclusively, shunning regular casts. This leads to errors like this:

但要注意:许多人陷入了as. 因为它不会抛出异常,所以有些人认为它是一个“安全”的转换,他们专门使用它,避免常规转换。这会导致如下错误:

(o as Animal).Speak();

In this case, the developer is clearly assuming that owill alwaysbe an Animal, and as long as their assumption is correct, everything works fine. But if they're wrong, then what they end up with here is a NullReferenceException. With a regular cast, they would have gotten an InvalidCastExceptioninstead, which would have more correctly identified the problem.

在这种情况下,开发商显然是假设o永远是一个Animal,只要他们的假设是正确的,一切工作正常。但如果他们错了,那么他们最终得到的是一个NullReferenceException. 使用常规演员表,他们会得到一个InvalidCastException替代,这将更正确地识别问题。

Sometimes, this bug can be hard to find:

有时,这个错误很难找到:

class Foo{
    readonly Animal animal;

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

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

This is another case where the developer is clearly expecting oto be an Animalevery time, but this isn't obvious in the constructor, where the ascast is used. It's not obvious until you get to the Interactmethod, where the animalfield is expected to be positively assigned. In this case, not only do you end up with a misleading exception, but it isn't thrown until potentially much later than when the actual error occurred.

这是开发人员显然希望每次o都是 an 的另一种情况Animal,但这在使用强制转换的构造函数中并不明显as。直到您进入该Interact方法时,这并不明显,在该方法中该animal字段预计会被积极分配。在这种情况下,您不仅会以误导性异常告终,而且直到可能比实际错误发生时间晚得多才会抛出异常。

In summary:

总之:

  • If you only need to know whether or not an object is of some type, use is.

  • If you need to treat an object as an instance of a certain type, but you don't know for sure that the object will be of that type, use asand check for null.

  • If you need to treat an object as an instance of a certain type, and the object is supposed to be of that type, use a regular cast.

  • 如果您只需要知道对象是否属于某种类型,请使用is.

  • 如果您需要将对象视为某种类型的实例,但您不确定该对象是否属于该类型,请使用as并检查null.

  • 如果您需要将一个对象视为某种类型的实例,并且该对象应该属于该类型,请使用常规强制转换。

回答by Yahoo Serious

I had a Type-property to compare to and could not use is(like my_type is _BaseTypetoLookFor), but I could use these:

我有一个Type-property 来比较并且不能使用is(比如my_type is _BaseTypetoLookFor),但我可以使用这些:

base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);

Notice that IsInstanceOfTypeand IsAssignableFromreturn truewhen comparing the same types, where IsSubClassOf will return false. And IsSubclassOfdoes not work on interfaces, where the other two do. (See also this question and answer.)

请注意,IsInstanceOfTypeIsAssignableFrom回报true比较相同类型时,其中IsSubClassOf将返回false。并且IsSubclassOf不适用于其他两个接口的接口。(另请参阅此问答。)

public class Animal {}
public interface ITrainable {}
public class Dog : Animal, ITrainable{}

Animal dog = new Dog();

typeof(Animal).IsInstanceOfType(dog);     // true
typeof(Dog).IsInstanceOfType(dog);        // true
typeof(ITrainable).IsInstanceOfType(dog); // true

typeof(Animal).IsAssignableFrom(dog.GetType());      // true
typeof(Dog).IsAssignableFrom(dog.GetType());         // true
typeof(ITrainable).IsAssignableFrom(dog.GetType()); // true

dog.GetType().IsSubclassOf(typeof(Animal));            // true
dog.GetType().IsSubclassOf(typeof(Dog));               // false
dog.GetType().IsSubclassOf(typeof(ITrainable)); // false

回答by androidrill

You can use "typeof()" operator in C# but you need to call the namespace using System.IO; You must use "is" keyword if you wish to check for a type.

您可以在 C# 中使用“typeof()”运算符,但您需要使用 System.IO 调用命名空间;如果要检查类型,则必须使用“is”关键字。