1736

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

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

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

4

14 回答 14

2078

都是不同的。

  • 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"
于 2009-06-11T19:15:50.107 回答
228

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

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

Foo foo = obj as Foo;

if (foo != null)
    // your code here

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

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

需要两个

更新(2020 年 1 月):

  • 从 C# 7+开始,您现在可以进行内联转换,因此“is”方法现在也可以在一次转换中完成。

例子:

if(obj is Foo newLocalFoo)
{
    // For example, you can now reference 'newLocalFoo' in this local scope
    Console.WriteLine(newLocalFoo);
}
于 2009-06-11T19:14:42.620 回答
87

1.

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

这是非法的,因为typeof仅适用于类型,不适用于变量。我假设 obj1 是一个变量。所以,这种方式typeof是静态的,并且在编译时而不是运行时完成它的工作。

2.

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

这就是trueifobj1正是 type int。ifobj1派生自int,if 条件为false

3.

if (obj1 is int)

true如果它是obj1一个int,或者它派生自一个名为 的类int,或者它实现了一个名为 的接口int

于 2009-06-11T19:17:26.013 回答
57
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",因为类型oDog,不是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替代品,这样可以更正确地识别问题。

有时,这个错误很难找到:

class Foo{
    readonly Animal animal;

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

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

这是另一种情况,开发人员显然希望每次o都是一个,但这在使用强制转换的构造函数中并不明显。在您使用该方法之前并不明显,该方法预计该字段将被积极分配。在这种情况下,您不仅最终会得到一个误导性的异常,而且直到可能比实际错误发生的时间晚得多时才会抛出它。AnimalasInteractanimal

总之:

  • 如果您只需要知道对象是否属于某种类型,请使用is.

  • 如果您需要将对象视为某种类型的实例,但您不确定该对象是否属于该类型,请使用as并检查null.

  • 如果您需要将对象视为某种类型的实例,并且该对象应该属于该类型,请使用常规强制转换。

于 2009-06-11T19:34:01.293 回答
18

如果您使用的是 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 的评论更新了更长的新方法以使用开关。

于 2018-02-01T15:47:47.077 回答
15

我有一个Type-property 可以比较并且不能使用is(如my_type is _BaseTypetoLookFor),但我可以使用这些:

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

请注意,IsInstanceOfType在比较相同类型时,将返回,其中 IsSubClassOf 将IsAssignableFrom返回。并且不适用于其他两个接口的接口。(另请参阅此问题和答案。)truefalseIsSubclassOf

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
于 2012-05-15T10:39:10.817 回答
11

我更喜欢的是

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

假设 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
  }
}
于 2009-06-11T19:15:16.317 回答
5

我相信最后一个也关注继承(例如 Dog is Animal == true),这在大多数情况下更好。

于 2009-06-11T19:14:00.267 回答
3

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

于 2009-06-11T19:14:42.230 回答
0

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

于 2009-06-11T19:16:12.727 回答
0

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

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
    */
于 2016-04-14T07:17:08.423 回答
-4
if (c is UserControl) c.Enabled = enable;
于 2016-08-12T10:31:34.420 回答
-5

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

于 2014-04-03T11:06:31.357 回答
-5

性能测试 typeof() 与 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
于 2015-08-03T13:58:53.627 回答