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
Type Checking: typeof, GetType, or is?
提问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.
都是不同的。
typeof
takes a type name (which you specify at compile time).GetType
gets the runtime type of an instance.is
returns 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 typeof
when you want to get the type at compilation time. Use GetType
when you want to get the type at execution time. There are rarely any cases to use is
as 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 typeof
only works on types, not on variables. I assume obj1 is a variable. So, in this way typeof
is static, and does its work at compile time instead of runtime.
这是非法的,因为typeof
只适用于类型,而不适用于变量。我假设 obj1 是一个变量。因此,这种方式typeof
是静态的,并且在编译时而不是运行时完成其工作。
2.
2.
if (obj1.GetType() == typeof(int))
This is true
if obj1
is exactly of type int
. If obj1
derives from int
, the if condition will be false
.
这就是true
ifobj1
类型int
。如果obj1
派生自int
,则 if 条件将为false
。
3.
3.
if (obj1 is int)
This is true
if obj1
is an int
, or if it derives from a class called int
, or if it implements an interface called int
.
这是true
ifobj1
是一个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 o
is Dog
, not Animal
. You can make this work, however, if you use the IsAssignableFrom
method of the Type
class.
这将打印"o is something else"
,因为类型o
is 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 is
keyword. Hence, if this is the behavior you want, you should use the is
keyword, which is more readable and more efficient.
有了这个,你就有了is
关键字的等效行为。因此,如果这是您想要的行为,您应该使用is
关键字,它更具可读性和效率。
if(o is Animal)
Console.WriteLine("o is an animal");
In most cases, though, the is
keyword 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 is
operator, and if o
is 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 as
operator 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 o
will 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 InvalidCastException
instead, 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 o
to be an Animal
every time, but this isn't obvious in the constructor, where the as
cast is used. It's not obvious until you get to the Interact
method, where the animal
field 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
as
and check fornull
.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 IsInstanceOfType
and IsAssignableFrom
return true
when comparing the same types, where IsSubClassOf will return false
. And IsSubclassOf
does not work on interfaces, where the other two do. (See also this question and answer.)
请注意,IsInstanceOfType
与IsAssignableFrom
回报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”关键字。