如果不需要转换,并且需要检查对象的最具体(运行时)类型,哪个更快? .GetType() & typeof(),还是运算符?
If you need no casting, and you need to check the most specific (runtime) type of an object, which is faster? .GetType() & typeof(), or is operator?
1) .GetType()
将 return 调用它的对象的运行时类型,
这是继承层次结构中最具体的类型。您可以使用 typeof()
为类名
获取 Type
的函数
2) is 运算符将检查左侧对象的类型
是右侧指定类型的子类型或相同类型
3) 鉴于您只需要检查对象的最具体类型,并且不需要转换,前者 (1) 是否比后者 (2) 快得多?
4) is
运算符是否实际执行转换并检查是否为 null,或者
此行为已在更高版本的 C Sharp 中修改?
typeof(x)
就是得到一个Literal类型的Type-Object,比如typeof(int)
。这是一个运行时常量。
对于 object.GetType()
你需要一个对象实例。
if (x is IList)
is 运算符进行强制转换,但 returns bool 表示成功,如果 x 为 null 或不兼容类型,则为 false。
有
if (x is IList list)
您可以同时进行布尔测试和转换。
没意义,谈性能,因为完全不同的操作。
如果你想获取对象实例的类型 object.GetType()
是你唯一的选择,但你可以再次测试它,如
x.GetType() == typeof(List)
虽然你可以确定
x.GetType() == typeof(IList)
将始终为 false,因为 GetType 永远不会 return 接口的类型。
对于此测试,您需要
typeof(IList).IsAssignableFrom(x.GetType());
第一个 4) 因为它更简单。 is
运算符与 as
运算符一起实现。
x is C
与
相同
x as C != null
源码可以看the fabulous Eric Lippert's blog。目前(提交 e09c42a),Roslyn 编译器将两者都转换为
isinst C
ldnull
cgt.un
其中 isinst
是尝试将 x
转换为 C
并将转换后的引用留在堆栈顶部的魔法指令,如果失败则为 null
.剩下的两条指令是检查 null
.
至于性能,不好说。理论上,使用 is
检查应该更快,因为它是一个内置的 CLR 指令,针对它的作用进行了高度优化,而另一个检查必须调用三种方法,GetType()
、GetTypeFromHandle(RuntimeTypeHandle)
和 Type
上的等式。还有涉及调用 GetType()
的标准检查 null 和抛出 NRE。一个非常粗略的基准支持这个假设:link to DotNetFiddle。如果有人愿意执行更复杂的基准测试,请继续。
显然,我可以想象您可以拥有如此深和复杂的继承层次结构,is
检查将比 GetType()
的任何开销花费更长的时间。随意将我的基准子类型提高到 C100 并检查是否足够:)
编辑:
我想我应该补充一点,这个讨论纯粹是理论上的。在生产代码中,您应该使用 x is C
,因为它简洁且更健壮,因为它会检查整个层次结构以进行子类型化。如果您有一个热路径来检查给定实例的类型,并且您知道层次结构是扁平的,那么您可能应该重新设计系统以避免该检查,而不是通过丑化代码来挤出一些性能。
1) .GetType()
将 return 调用它的对象的运行时类型,
这是继承层次结构中最具体的类型。您可以使用 typeof()
为类名
获取 Type
的函数
2) is 运算符将检查左侧对象的类型
是右侧指定类型的子类型或相同类型
3) 鉴于您只需要检查对象的最具体类型,并且不需要转换,前者 (1) 是否比后者 (2) 快得多?
4) is
运算符是否实际执行转换并检查是否为 null,或者
此行为已在更高版本的 C Sharp 中修改?
typeof(x)
就是得到一个Literal类型的Type-Object,比如typeof(int)
。这是一个运行时常量。
对于 object.GetType()
你需要一个对象实例。
if (x is IList)
is 运算符进行强制转换,但 returns bool 表示成功,如果 x 为 null 或不兼容类型,则为 false。 有
if (x is IList list)
您可以同时进行布尔测试和转换。
没意义,谈性能,因为完全不同的操作。
如果你想获取对象实例的类型 object.GetType()
是你唯一的选择,但你可以再次测试它,如
x.GetType() == typeof(List)
虽然你可以确定
x.GetType() == typeof(IList)
将始终为 false,因为 GetType 永远不会 return 接口的类型。 对于此测试,您需要
typeof(IList).IsAssignableFrom(x.GetType());
第一个 4) 因为它更简单。 is
运算符与 as
运算符一起实现。
x is C
与
相同x as C != null
源码可以看the fabulous Eric Lippert's blog。目前(提交 e09c42a),Roslyn 编译器将两者都转换为
isinst C
ldnull
cgt.un
其中 isinst
是尝试将 x
转换为 C
并将转换后的引用留在堆栈顶部的魔法指令,如果失败则为 null
.剩下的两条指令是检查 null
.
至于性能,不好说。理论上,使用 is
检查应该更快,因为它是一个内置的 CLR 指令,针对它的作用进行了高度优化,而另一个检查必须调用三种方法,GetType()
、GetTypeFromHandle(RuntimeTypeHandle)
和 Type
上的等式。还有涉及调用 GetType()
的标准检查 null 和抛出 NRE。一个非常粗略的基准支持这个假设:link to DotNetFiddle。如果有人愿意执行更复杂的基准测试,请继续。
显然,我可以想象您可以拥有如此深和复杂的继承层次结构,is
检查将比 GetType()
的任何开销花费更长的时间。随意将我的基准子类型提高到 C100 并检查是否足够:)
编辑:
我想我应该补充一点,这个讨论纯粹是理论上的。在生产代码中,您应该使用 x is C
,因为它简洁且更健壮,因为它会检查整个层次结构以进行子类型化。如果您有一个热路径来检查给定实例的类型,并且您知道层次结构是扁平的,那么您可能应该重新设计系统以避免该检查,而不是通过丑化代码来挤出一些性能。