我见过很多人使用以下代码:
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
就我个人而言,我觉得最后一个是最干净的,但有什么我想念的吗?哪一个最好用,还是个人偏好?
答案 0 :(得分:1671)
一切都不同。
typeof
采用类型名称(您在编译时指定)。GetType
获取实例的运行时类型。is
返回true。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总是表达式的类型。请记住,泛型方法基本上是一组具有适当类型的方法。例如:
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"
答案 1 :(得分:179)
如果要在编译时获取类型,请使用typeof
。如果要在执行时间获取类型,请使用GetType
。很少有任何情况可以使用is
,因为它会进行投射,并且在大多数情况下,无论如何最终都会投射变量。
您还没有考虑过第四个选项(特别是如果您要将对象转换为您找到的类型);那就是使用as
。
Foo foo = obj as Foo;
if (foo != null)
// your code here
这只使用一次演员,而这种做法:
if (obj is Foo)
Foo foo = (Foo)obj;
需要两个。
答案 2 :(得分:66)
<强> 1 强>
Type t = typeof(obj1);
if (t == typeof(int))
这是非法的,因为typeof仅适用于类型,而不适用于变量。我假设obj1是一个变量。因此,以这种方式,typeof是静态的,并且它在编译时而不是运行时工作。
<强> 2 强>
if (obj1.GetType() == typeof(int))
如果obj1完全是int类型,则为true。如果obj1派生自int,那么if条件将为false。
第3 强>
if (obj1 is int)
如果obj1是int,或者它派生自一个名为int的类,或者它实现了一个名为int的接口,那么这是真的。
答案 3 :(得分:46)
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
代替,这样可以更准确地识别问题。
有时候,这个bug很难找到:
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
并检查{{1 }}
如果您需要将对象视为某种类型的实例,并且该对象应该属于该类型,请使用常规强制转换。
答案 4 :(得分:13)
我有Type
- 要比较的属性,但无法使用is
(例如my_type is _BaseTypetoLookFor
),但我可以使用这些:
base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);
请注意,在比较相同类型时,IsInstanceOfType
和IsAssignableFrom
会返回true
,其中IsSubClassOf将返回false
。并且IsSubclassOf
不适用于接口,其他两个接口也适用。 (另见this question and answer。)
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
答案 5 :(得分:11)
如果你正在使用C#7,那么现在是时候更新Andrew Hare的好答案了。 protractor-multiple-cucumber-html-reporter-plugin引入了一个很好的快捷方式,它在if语句的上下文中提供了一个类型变量,而不需要单独的声明/强制转换和检查:
if (obj1 is int integerValue)
{
integerValue++;
}
对于像这样的单人演员来说,这看起来相当平庸,但是当你有很多可能的类型进入你的日常生活时,真的很闪耀。以下是避免施放两次的旧方法:
Button button = obj1 as Button;
if (button != null)
{
// do stuff...
return;
}
TextBox text = obj1 as TextBox;
if (text != null)
{
// do stuff...
return;
}
Label label = obj1 as Label;
if (label != null)
{
// do stuff...
return;
}
// ... and so on
尽可能地缩小这段代码,以及避免同一对象的重复演员一直困扰着我。上面的模式匹配很好地压缩了以下内容:
switch (obj1)
{
case Button button:
// do stuff...
break;
case TextBox text:
// do stuff...
break;
case Label label:
// do stuff...
break;
// and so on...
}
编辑:根据Palec的评论更新了使用交换机的更长的新方法。
答案 6 :(得分:8)
我更喜欢是
也就是说,如果您正在使用 ,那么您可能 正确使用继承。
假设Person:Entity和那个Animal:Entity。 Feed是实体中的一种虚拟方法(让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
}
}
答案 7 :(得分:5)
我相信最后一个也看待继承(例如Dog is Animal == true),这在大多数情况下更好。
答案 8 :(得分:2)
这取决于我在做什么。如果我需要一个bool值(比如,确定我是否会转换为int),我将使用is
。如果我出于某种原因确实需要这种类型(比方说,传递给其他方法),我将使用GetType()
。
答案 9 :(得分:0)
最后一个更干净,更明显,还检查子类型。其他人不检查多态性。
答案 10 :(得分:0)
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
*/
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
*/
答案 11 :(得分:-3)
if (c is UserControl) c.Enabled = enable;
答案 12 :(得分:-5)
您可以使用&#34; typeof()&#34; C#中的运算符,但您需要使用System.IO调用命名空间;你必须使用&#34;是&#34;如果您想检查类型,请使用关键字。
答案 13 :(得分:-5)
性能测试typeof()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();
}
}
调试模式的结果:
00:00:08.4096636
00:00:10.8570657
发布模式的结果:
00:00:02.3799048
00:00:07.1797128