types检查:typeof,GetType,或者是?

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

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

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

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

或这个:

 if (obj1 is int) // Some code here 

就我个人而言,我觉得最后一个是最干净的,但有什么我失踪? 哪一个最好用,还是个人喜好?

一切都不一样

  • typeof需要一个types名称(在编译时指定)。
  • GetType获取实例的运行时types。
  • 如果实例在inheritance树中, is返回true。

 class Animal { } class Dog : Animal { } void PrintTypes(Animal a) { print(a.GetType() == typeof(Animal)) // false print(a is Animal) // true print(a.GetType() == typeof(Dog)) // true } Dog spot = new Dog(); PrintTypes(spot); 

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

是。 T始终是expression式的types。 请记住,一个通用的方法基本上是一大堆适当types的方法。 例:

 string Foo<T>(T object) { 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" 

当你想在编译时获得types的时候使用typeof 。 如果您想在执行时获取types,请使用GetType 。 几乎没有任何情况下使用is因为它是一个演员,并在大多数情况下,最终你最终铸造variables。

还有第四个选项,你没有考虑过(特别是如果你要把一个对象的types,你也发现); 那就是as

 Foo foo = obj as Foo; if (foo != null) // your code here 

这只使用一个演员,而这种方法:

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

需要两个

1。

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

这是非法的,因为typeof只适用于types,而不是variables。 我假设obj1是一个variables。 所以,typeof是静态的,在编译时而不是运行时工作。

2。

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

如果obj1正好是inttypes,则这是真的。 如果obj1从int派生,则if条件将为false。

3。

 if (obj1 is int) 

如果obj1是一个int,或者它是从一个名为int的类派生的,或者它实现了一个名为int的接口,则这是真的。

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

这是一个错误。 C#中的typeof运算符只能使用types名称,而不能使用对象。

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

这会起作用,但也许不像你所期望的那样。 对于值types,正如你在这里显示的那样,这是可以接受的,但是对于引用types,只有当types是完全相同的types时才返回true,而在inheritance层次结构中则不是。 例如:

 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的types是Dog ,而不是Animal 。 但是,如果使用Type类的IsAssignableFrom方法,则可以完成此工作。

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

不过,这种技术仍然存在一个主要问题。 如果你的variables为null,那么对GetType()的调用将抛出一个NullReferenceExceptionexception。 所以为了使它正常工作,你可以这样做:

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

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

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

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

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

但是这使得CLR最多可以检查对象的types两次。 它会检查一次,以满足is运算符,如果o确实是一个Animal ,我们再次检查以validation演员。

相反,这样做效率更高:

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

as运算符是一个强制转换,如果失败则不会抛出exception,而是返回null 。 这样,CLR只检查一次对象的types,之后我们只需要做一个空的检查,效率更高。

但要小心:许多人陷入了陷阱。 因为它不会抛出exception,所以有些人把它看作是一个“安全”的表演,他们完全使用它,回避正常的表演。 这导致这样的错误:

 (o as Animal).Speak(); 

在这种情况下,开发人员明确地假设o 总是一个Animal ,只要他们的假设是正确的,一切正常。 但是,如果他们错了,那么他们最终在这里是一个NullReferenceException 。 如果使用正则expression式,他们会得到一个InvalidCastException而这会更准确地发现问题。

有时候,这个bug很难find:

 class Foo{ readonly Animal animal; public Foo(object o){ animal = o as Animal; } public void Interact(){ animal.Speak(); } } 

这是另一种情况,开发人员显然希望o每次都是一个Animal ,但是这在构造函数中并不明显。 直到你达到Interact方法, animal领域才能被正确地分配,这是不明显的。 在这种情况下,不仅会导致一个误导性的exception,而且在发生实际错误之前,不会抛出exception。

综上所述:

  • 如果您只需要知道某个对象是否属于某种types,则使用is

  • 如果您需要将某个对象作为某个特定types的实例对待,但不确定该对象是否属于该types,请使用as并检查null

  • 如果您需要将对象视为某个types的实例,并且该对象应该是该types的,请使用常规的强制转换。

我有一个Type属性来比较和不能使用is (像my_type is _BaseTypetoLookFor ),但我可以使用这些:

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

请注意, IsAssignableFromIsAssignableFrom在比较相同types时返回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 

我更喜欢的

也就是说,如果你使用的 ,你可能没有正确使用inheritance。

假设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 } } } 

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

我相信最后一个也看inheritance(例如狗是动物==真),这在大多数情况下更好。

这取决于我在做什么。 如果我需要一个布尔值(比如说,以确定我是否会投到int),我会使用is 。 如果我真的需要某种原因的types(比如传递给其他方法),我将使用GetType()

用于获取types的System.Type对象。 typesexpression式采用以下forms:

 System.Type type = typeof(int); Example: public class ExampleClass { public int sampleMember; public void SampleMethod() {} static void Main() { Type t = typeof(ExampleClass); // Alternatively, you could use // ExampleClass obj = new ExampleClass(); // Type t = obj.GetType(); Console.WriteLine("Methods:"); System.Reflection.MethodInfo[] methodInfo = t.GetMethods(); foreach (System.Reflection.MethodInfo mInfo in methodInfo) Console.WriteLine(mInfo.ToString()); Console.WriteLine("Members:"); System.Reflection.MemberInfo[] memberInfo = t.GetMembers(); foreach (System.Reflection.MemberInfo mInfo in memberInfo) Console.WriteLine(mInfo.ToString()); } } /* Output: Methods: Void SampleMethod() System.String ToString() Boolean Equals(System.Object) Int32 GetHashCode() System.Type GetType() Members: Void SampleMethod() System.String ToString() Boolean Equals(System.Object) Int32 GetHashCode() System.Type GetType() Void .ctor() Int32 sampleMember */ 

本示例使用GetType方法来确定用于包含数值计算结果的types。 这取决于结果编号的存储要求。

  class GetTypeTest { static void Main() { int radius = 3; Console.WriteLine("Area = {0}", radius * radius * Math.PI); Console.WriteLine("The type is {0}", (radius * radius * Math.PI).GetType() ); } } /* Output: Area = 28.2743338823081 The type is System.Double */ 

最后一个更清晰,更明显,也检查子types。 其他人不检查多态性。

 if (c is UserControl) c.Enabled = enable; 

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

性能testingtypeof()vs GetType():

 using System; namespace ConsoleApplication1 { class Program { enum TestEnum { E1, E2, E3 } static void Main(string[] args) { { var start = DateTime.UtcNow; for (var i = 0; i < 1000000000; i++) Test1(TestEnum.E2); Console.WriteLine(DateTime.UtcNow - start); } { var start = DateTime.UtcNow; for (var i = 0; i < 1000000000; i++) Test2(TestEnum.E2); Console.WriteLine(DateTime.UtcNow - start); } Console.ReadLine(); } static Type Test1<T>(T value) => typeof(T); static Type Test2(object value) => value.GetType(); } } 

结果在debugging模式下:

 00:00:08.4096636 00:00:10.8570657 

结果在发布模式:

 00:00:02.3799048 00:00:07.1797128