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

C# 类型检查:typeof、GetType或is?,c#,types,typeof,gettype,C#,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 就我个人而言,我觉得最后一个是最干净的,但我有什么遗漏吗?哪一个是最好的选择,还是个人偏好?我相信最后

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

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

就我个人而言,我觉得最后一个是最干净的,但我有什么遗漏吗?哪一个是最好的选择,还是个人偏好?

我相信最后一个选择也会考虑遗传(例如,Dog is Animal==true),这在大多数情况下更好。

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

当您想要在编译时获取该类型时,使用
typeof
。要在执行时获取类型,请使用
GetType
。很少有任何情况可以使用
is
,因为它执行强制转换,而且在大多数情况下,您最终还是强制转换了变量

还有第四个选项您没有考虑(特别是如果您要将对象强制转换为您找到的类型);即使用
作为

Foo foo = obj as Foo;

if (foo != null)
    // your code here
此方法仅使用一个cast,而此方法:

if (obj is Foo)
    Foo foo = (Foo)obj;
需要两个

更新(2020年1月):

  • ,您现在可以内联转换,因此“is”方法现在也可以在一次转换中完成
例如:

if(obj是Foo newLocalFoo)
{
//例如,您现在可以在此本地范围中引用“newLocalFoo”
Console.WriteLine(newLocalFoo);
}
我更喜欢的是

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

假设那个人是实体,那个动物是实体。Feed是实体中的虚拟方法(使Neil高兴)

班级人员
{
//一个人应该能够养活自己
//另一个实体,但他们知道他供养的方式
//每一个都是不同的
公共覆盖无效提要(实体e)
{
如果(e是人)
{
//喂我
}
否则,如果(e是动物)
{
//皱褶
}
}
}
相当于

班级人员
{
公共覆盖无效提要(人员p)
{
//喂人
}
公共饲料(动物a)
{
//喂动物
}
}
所有这些都是不同的

  • typeof
    采用类型名称(在编译时指定)
  • GetType
    获取实例的运行时类型
  • is
    如果实例位于继承树中,则返回true
例子
(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"
stringfoo(T参数){returntypeof(T).Name;}
动物可能是新狗;
狗肯定是新狗;
福(可能是狗);//这将调用Foo并返回“Animal”
福(可能是狗);//这与上面完全相同
福(可能是狗);/!!!这将无法编译。参数需要狗,不能传入动物。
Foo(绝对是狗);//这将调用Foo并返回“Dog”
Foo(绝对是狗);//这与上面完全相同。
Foo(绝对是狗);//这将调用Foo并返回“Animal”。
Foo((动物)绝对是狗);//这与上面的操作相同,返回“Animal”

最后一个更清晰、更明显,并且还检查子类型。其他人不检查多态性。

1。

Type t = typeof(obj1);
if (t == typeof(int))
if (obj1.GetType() == typeof(int))
if (obj1 is int)
这是非法的,因为
typeof
只对类型有效,对变量无效。我假设obj1是一个变量。因此,通过这种方式,
typeof
是静态的,它在编译时而不是运行时工作

2.

Type t = typeof(obj1);
if (t == typeof(int))
if (obj1.GetType() == typeof(int))
if (obj1 is int)
如果
obj1
的类型正好是
int
,则这是
true
。如果
obj1
源自
int
,则If条件将为
false

3.

Type t = typeof(obj1);
if (t == typeof(int))
if (obj1.GetType() == typeof(int))
if (obj1 is int)
如果
obj1
是一个
int
,或者它派生自一个名为
int
的类,或者它实现了一个名为
int
的接口,则这是
true

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是其他东西”
,因为
o
的类型是
Dog
,而不是
Animal
。但是,如果使用
Type
类的
IsAssignableFrom
方法,则可以实现这一点

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();
(o as Animal).Speak();
但这会使CLR最多检查两次对象的类型。它将对其进行一次检查,以满足
is
操作员的要求,如果
o
确实是
动物
,我们将再次对其进行检查以验证投射

这样做更有效:

Animal a = o as Animal;
if(a != null)
    a.Speak();
as
运算符是一个强制转换,如果失败,它不会抛出异常,而是返回
null
。这样,CLR将检查对象的类型
00:00:02.3799048
00:00:07.1797128
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
    */
if (c is UserControl) c.Enabled = enable;
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...
}