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

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

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

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

或者这个:

if (obj1 is int)
    // Some code here

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


当前回答

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

其他回答

我发现,通过以下方法检查某个事物的类型是否等于某个事物:

variableName.GetType()==typeof(int)

用于获取类型的System.Type对象。表达式类型采用以下形式:

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方法确定用于包含数值计算结果的类型。这取决于生成的数字的存储要求。

    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
    */

如果您使用的是C#7,那么是时候更新Andrew Hare的伟大答案了。模式匹配引入了一个很好的快捷方式,它在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的评论,更新了较长的新方法以使用开关。

一切都不同。

typeof采用类型名(您在编译时指定)。GetType获取实例的运行时类型。如果实例在继承树中,则返回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);

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"
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的类型是狗,而不是动物。但是,如果使用Type类的IsAssignableFrom方法,则可以实现这一点。

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

然而,这一技术仍然存在一个主要问题。如果变量为空,则对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永远是动物,只要他们的假设是正确的,一切都正常。但如果他们错了,那么他们最终会得到一个NullReferenceException。如果使用常规强制转换,则会得到InvalidCastException,这将更正确地识别问题。

有时,这个bug很难找到:

class Foo{
    readonly Animal animal;

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

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

这是另一种情况,开发人员显然希望o每次都是Animal,但这在构造函数中并不明显,在构造函数中使用了as cast。在使用Interactive方法之前,这是不明显的,在该方法中,动物场将被正向分配。在这种情况下,不仅会导致一个误导性的异常,而且在可能比实际错误发生的时间晚得多的时候才会引发异常。

总而言之:

如果您只需要知道一个对象是否属于某种类型,请使用。如果您需要将对象视为某一类型的实例,但不确定该对象是否为该类型,请使用as并检查是否为null。如果需要将对象视为某个类型的实例,并且该对象应该是该类型的,请使用常规强制转换。