C# 如果不需要强制转换,并且需要检查对象的最特定(运行时)类型,哪种类型更快。GetType()&typeof(),或者是运算符?

C# 如果不需要强制转换,并且需要检查对象的最特定(运行时)类型,哪种类型更快。GetType()&typeof(),或者是运算符?,c#,casting,typeof,gettype,C#,Casting,Typeof,Gettype,1.GetType将返回调用它的对象的运行时类型, 这是继承层次结构中最具体的类型。你可以使用 函数获取类名的类型 2 is操作员将检查左侧物体的类型 是的子类型,或与右侧指定的类型相同 3考虑到您只需要检查最特定类型的对象,并且不需要进行铸造,那么前一个1是否比后一个2快得多? 4 is运算符是否实际执行强制转换并检查null,或 在C Sharp的更高版本中,此行为已被修改。typeofx是为了获得文本类型的Type对象,如TypeOfIt。这是一个运行时常量 对于object.GetTyp

1.GetType将返回调用它的对象的运行时类型, 这是继承层次结构中最具体的类型。你可以使用 函数获取类名的类型 2 is操作员将检查左侧物体的类型 是的子类型,或与右侧指定的类型相同 3考虑到您只需要检查最特定类型的对象,并且不需要进行铸造,那么前一个1是否比后一个2快得多? 4 is运算符是否实际执行强制转换并检查null,或 在C Sharp的更高版本中,此行为已被修改。

typeofx是为了获得文本类型的Type对象,如TypeOfIt。这是一个运行时常量

对于object.GetType,您需要一个对象实例

 if (x is IList)
is运算符执行强制转换,但在成功时返回bool,如果x为null或类型不兼容,则返回false。 与

您可以同时执行布尔测试和强制转换

谈论性能是没有意义的,因为它们是完全不同的操作

如果要获取对象实例的类型,object.GetType是您唯一的选项,但您可以像这样重新测试它

 x.GetType() == typeof(List)
虽然你可以肯定

 x.GetType() == typeof(IList)
将始终为false,因为GetType永远不会返回接口的类型。 对于这个测试,您需要

typeof(IList).IsAssignableFrom(x.GetType());
typeofx是获取文本类型的类型对象,如TypeOfIT。这是一个运行时常量

对于object.GetType,您需要一个对象实例

 if (x is IList)
is运算符执行强制转换,但在成功时返回bool,如果x为null或类型不兼容,则返回false。 与

您可以同时执行布尔测试和强制转换

谈论性能是没有意义的,因为它们是完全不同的操作

如果要获取对象实例的类型,object.GetType是您唯一的选项,但您可以像这样重新测试它

 x.GetType() == typeof(List)
虽然你可以肯定

 x.GetType() == typeof(IList)
将始终为false,因为GetType永远不会返回接口的类型。 对于这个测试,您需要

typeof(IList).IsAssignableFrom(x.GetType());

前4个,因为它更简单。is运算符由as运算符实现

x is C

x as C != null
您可以查看的源代码。目前提交e09c42a时,Roslyn编译器将这两种代码都转换为

isinst C
ldnull
cgt.un
其中isinst是一条神奇的指令,它尝试将x强制转换为C,并将强制转换的引用保留在堆栈顶部,如果失败,则返回null。剩下的两条指令是检查null

至于表现,很难说是肯定的。理论上,使用is进行检查应该更快,因为它是一个内置的CLR指令,针对它的功能进行了大量优化,而另一个检查必须调用三个方法:GetType、GetTypeFromHandleRuntimeTypeHandle和equality on Type。调用GetType时还涉及对null和throw NRE的标准检查。一个非常粗糙的基准支持这一假设:。如果有人愿意执行更复杂的基准测试,请继续

显然,我可以想象您可能有一个如此深刻和复杂的继承层次结构,is检查将花费比任何GetType开销都要长的时间。请随意将我的基准分为C100以下的子类型,并检查这是否足够:

编辑:
我想我应该补充一点,这种讨论纯粹是理论上的。在生产代码中,您应该使用x is C,因为它简洁且更健壮,因为它检查整个层次结构的子类型。如果您有一个热路径来检查给定实例的类型,并且您知道层次结构是扁平的,那么您可能应该重新设计系统以避免这种检查,而不是丑化代码以挤出一些性能。

前4个更简单。is运算符由as运算符实现

x is C

x as C != null
您可以查看的源代码。目前提交e09c42a时,Roslyn编译器将这两种代码都转换为

isinst C
ldnull
cgt.un
其中isinst是一条神奇的指令,它尝试将x强制转换为C,并将强制转换的引用保留在堆栈顶部,如果失败,则返回null。剩下的两条指令是检查null

至于表现,很难说是肯定的。理论上,使用is进行检查应该更快,因为它是一个内置的CLR指令,针对它的功能进行了大量优化,而另一个检查必须调用三个方法:GetType、GetTypeFromHandleRuntimeTypeHandle和equality on Type。调用GetType时还涉及对null和throw NRE的标准检查。一个非常粗糙的基准支持这一假设:。如果有人愿意执行更复杂的基准测试,请继续

显然,我可以想象您可能有一个如此深刻和复杂的继承层次结构,is检查将花费比任何GetType开销都要长的时间。请随意为我的长椅分类 hm标记到C100并检查是否足够:

编辑:
我想我应该补充一点,这种讨论纯粹是理论上的。在生产代码中,您应该使用x is C,因为它简洁且更健壮,因为它检查整个层次结构的子类型。如果您有一个检查给定实例类型的热路径,并且您知道层次结构是扁平的,那么您可能应该重新设计系统以避免这种检查,而不是丑化代码以挤出一些性能。

您深入挖掘,但您是对的。除此之外,GetType不是虚拟的,所有类型对象都是单例对象,所以比较它们只是比较引用。一个内置函数实际上对性能没有任何意义,因为IL到本机编译会再次进行一些优化。IL对i++一无所知,但尽管如此,JIT编译可能会使用INC指令。因此,更好的理由是。代码更短,更容易阅读。@Holger你说得对,我在虚拟机上搞砸了。缩短代码的理由是显而易见的,毕竟is是作为这类事情的语法糖引入的,它还检查继承层次结构中的子类型,而不仅仅是具体类型。而且,抖动也可以识别GetType==typeof模式并对其进行优化。我的猜测是可能的,但事实并非如此,因此,在CLR内部结构中进行查找比实际实例化类型对象并进行比较要快。除此之外,GetType不是虚拟的,所有类型对象都是单例对象,所以比较它们只是比较引用。一个内置函数实际上对性能没有任何意义,因为IL到本机编译会再次进行一些优化。IL对i++一无所知,但尽管如此,JIT编译可能会使用INC指令。因此,更好的理由是。代码更短,更容易阅读。@Holger你说得对,我在虚拟机上搞砸了。缩短代码的理由是显而易见的,毕竟is是作为这类事情的语法糖引入的,它还检查继承层次结构中的子类型,而不仅仅是具体类型。而且,抖动也可以识别GetType==typeof模式并对其进行优化。我的猜测是可能的,但事实并非如此,因此在CLR内部结构中的查找比实际实例化类型对象并比较它们要快。我想知道5.GetType==typeofint是否比5是Int32快。如果您针对最具体的具体类型进行测试,那么它们基本上会做相同的事情。比如,如果具体的类B和C继承自A,并且您想知道A类型的变量是否具有最特定的类型B,那么您可以同时使用aInstance is B和aInstance.GetType==typeOfB,但是您现在可以自己测试它了,不是吗?您可以使用秒表或性能分析器测量时间。它可能因机器而异。这两个函数不一样。如果您有一个从B派生的类D,那么实例B将在D和B上返回true。您不应该依靠某个类hiearchie进行任何编码。除非你声明B是密封的——在这种情况下,你两个代码片段可能真的是等效的。是的,我知道他们做的不一样。这就是为什么我在问题中描述了他们的所作所为。is运算符也适用于检查对象是否是RHS上类型的子类型。我写道,你们可以检查物体的实际类型。但在本例中,您可以选择使用任何一种。在本例中,编写只起作用的代码不是一个好主意。你必须用断言等来确保你的假设,所有这些都只是为了获得10纳秒。只有在这行代码上有一百万次迭代时,才能对其进行度量,然后可能会有更多的行,更容易优化性能。我想知道5.GetType==typeofint是否比5是Int32快。如果您针对最具体的具体类型进行测试,那么它们基本上会做相同的事情。比如,如果具体的类B和C继承自A,并且您想知道A类型的变量是否具有最特定的类型B,那么您可以同时使用aInstance is B和aInstance.GetType==typeOfB,但是您现在可以自己测试它了,不是吗?您可以使用秒表或性能分析器测量时间。它可能因机器而异。这两个函数不一样。如果您有一个从B派生的类D,那么实例B将在D和B上返回true。您不应该依靠某个类hiearchie进行任何编码。除非你声明B是密封的——在这种情况下,你两个代码片段可能真的是等效的。是的,我知道他们做的不一样。这就是为什么我在问题中描述了他们的所作所为。is运算符也适用于检查对象是否是RHS上类型的子类型。我写道,你们可以检查物体的实际类型。但是在这种情况下,你可以选择使用任何一种。写代码不是一个好主意
在这种情况下,t仅起作用。你必须用断言等来确保你的假设,所有这些都只是为了获得10纳秒。只有在这一行代码上有一百万次迭代的情况下,才能对其进行度量,然后可能会有更多的行,更容易优化性能。例如,如果T不是密封类型x.GetType==typeofT意味着x的精确运行时类型正好是T,而x是T意味着x的类型是T或从T派生或实现T的东西,或者其他允许引用转换为T的东西。即使对于密封类型,由于共变和逆变泛型参数,两者也可能不同。例如,设Func f==>a;。那么f is Func是真的,因为Func的协方差。在很多情况下,两者是不等价的。例如,如果T不是密封类型x.GetType==typeofT意味着x的精确运行时类型正好是T,而x是T意味着x的类型是T或从T派生或实现T的东西,或者其他允许引用转换为T的东西。即使对于密封类型,由于共变和逆变泛型参数,两者也可能不同。例如,设Func f==>a;。那么f是Func是真的,因为Func的协方差。