.Net判断一个对象是否为数值类型探讨总结(高营养含量,含最终代码及跑分)...

前一篇发出来后引发了积极的探讨,起到了抛砖引玉效果,感谢大家参与。

吐槽一下:这个问题比其看起来要难得多得多啊。

大家的讨论最终还是没有一个完全正确的答案,不过我根据讨论结果总结了一个差不多算是最终版的代码,这里分享出来,毕竟这是大家共同的智慧结晶,没有交流和碰撞就没有这段代码。

 

探讨贡献提名典礼

首先感谢 花生!~~ 以及 NETRUBE 提出了使用 GetTypeCode() 获取类型代码的方式,这个比 typeof() 的性能要高,但是有一点局限性,后面代码中会指出。

image

image

由 JTANS 以及 入夏 提出的 ValueType 判断也是有意义的,但显然仅仅做这个判断只能确定是否为值类型,还不能确定是否为我们要的数值类型。

image

image

由 石山不高 提出 Decimal 是非基元类型,这是正确的,我们在最终代码中对其进行了特殊处理。

image

由 花生 (为什么有两个叫花生的!(+﹏+)~)给出的代码比较完善,是比较具有总结性的讨论成果了,最接近最终版:

image

其存在的问题主要是 char 和 bool 类型还是会被当做数值,以及判断顺序需要小幅优化。

 

(可能也许大概差不离就是)最终版代码(也可能不是)

除了对上述存在问题的改进,还重新调整为3个方法,分别是用来判断是否为数值类型、可空数值类型及可空类型。

/// <summary>/// 判断是否为数值类型。/// </summary>/// <param name="t">要判断的类型</param>/// <returns>是否为数值类型</returns>public static bool IsNumericType(this Type t){var tc = Type.GetTypeCode(t);return (t.IsPrimitive && t.IsValueType && !t.IsEnum && tc != TypeCode.Char && tc != TypeCode.Boolean) || tc == TypeCode.Decimal;}/// <summary>/// 判断是否为可空数值类型。/// </summary>/// <param name="t">要判断的类型</param>/// <returns>是否为可空数值类型</returns>public static bool IsNumericOrNullableNumericType(this Type t){return t.IsNumericType() || (t.IsNullableType() && t.GetGenericArguments()[0].IsNumericType());}/// <summary>/// 判断是否为可空类型。/// 注意,直接调用可空对象的.GetType()方法返回的会是其泛型值的实际类型,用其进行此判断肯定返回false。/// </summary>/// <param name="t">要判断的类型</param>/// <returns>是否为可空类型</returns>public static bool IsNullableType(this Type t){return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);}

 

为了累死电脑而设计的测试用代码

使用这个测试代码跑可以通过,基本涵盖了常用类型。

[TestClass]public class BasicTest{[TestMethod]public void 数值类型判断测试(){for (int i = 0; i < 500000; i++){Assert.IsTrue((591).GetType().IsNumericType());Assert.IsTrue((31.131).GetType().IsNumericType());Assert.IsTrue((31.131f).GetType().IsNumericType());Assert.IsTrue(((Int64)31).GetType().IsNumericType());Assert.IsTrue((new decimal(31.351)).GetType().IsNumericType());Assert.IsTrue((new Decimal(31.351)).GetType().IsNumericType());Assert.IsTrue(((byte)31).GetType().IsNumericType());Assert.IsTrue(((UInt64)31).GetType().IsNumericType());Assert.IsTrue(((UIntPtr)31).GetType().IsNumericType());Assert.IsTrue(((short)31).GetType().IsNumericType());Assert.IsTrue(((Single)31).GetType().IsNumericType());Assert.IsTrue((typeof(Int64?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(UInt64?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(decimal?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(Decimal?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(UIntPtr?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(byte?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(Single?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(Double?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(float?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(double?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(int?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(short?)).IsNumericOrNullableNumericType());Assert.IsTrue((typeof(Nullable<Byte>)).IsNumericOrNullableNumericType());Assert.IsFalse(DateTime.Now.GetType().IsNumericType());Assert.IsFalse(TimeSpan.FromDays(2).GetType().IsNumericType());Assert.IsFalse("aacc".GetType().IsNumericType());Assert.IsFalse(System.UriPartial.Path.GetType().IsNumericType());Assert.IsFalse('c'.GetType().IsNumericType());Assert.IsFalse(false.GetType().IsNumericType());Assert.IsFalse((typeof(DateTime?)).IsNumericOrNullableNumericType());Assert.IsFalse((typeof(Char?)).IsNumericOrNullableNumericType());Assert.IsFalse((typeof(char?)).IsNumericOrNullableNumericType());Assert.IsFalse((typeof(System.UriPartial?)).IsNumericOrNullableNumericType());Assert.IsFalse((typeof(Boolean?)).IsNumericOrNullableNumericType());Assert.IsFalse((typeof(bool?)).IsNumericOrNullableNumericType());}}}

需指出的是:

这里对可空类型判断没有使用 GetType() 方法获取类型对象,因为我测试了一下,可空类型执行 GetType() 返回的仍然是不可空的原类型,直接进行判断是否为数值类型即可。

那么为什么还要做针对可空类型的判断呢?如果你试过在 ASP.Net Mvc 中获取到模型属性的 ModelMetadata 你就会知道,其 ModelType 属性返回的就是 Nullable<> 类型,可空类型的判断就是给这种情况使用的。

 

老外!不服跑个分?

6b1394a6gw1ejy5mn1n6wj20ga095mxk

JEFFERY YOU 提出应该做一个测试,确实数据最有说服力。

我们就以上面的测试代码来跑,注意这是循环五十万轮的测试,每轮执行该方法36次,共计执行一千八百万次,我们让代码连续跑三遍,取第三遍的时间结果(第一遍的包含初始化流程,肯定会慢一些)。

我们的代码测试结果:

image

可以看出这个效率还是蛮高的,平均每轮耗时:0.016546毫秒,平均每次执行方法耗时:0.0004596111111毫秒

然后我们把老外的代码拿过来看一下,它跑不通这个测试,因为以下类型它没做判断:Decimal、Byte、UIntPtr 。

还有个我们测试代码之外的 IntPtr 。

加上这些类型的判断之后,主体方法代码如下:

return t == typeof(int)|| t == typeof(double)|| t == typeof(long)|| t == typeof(short)|| t == typeof(float)|| t == typeof(Int16)|| t == typeof(Int32)|| t == typeof(Int64)|| t == typeof(uint)|| t == typeof(UInt16)|| t == typeof(UInt32)|| t == typeof(UInt64)|| t == typeof(sbyte)|| t == typeof(Single)|| t == typeof(Decimal)|| t == typeof(Byte)|| t == typeof(UIntPtr)|| t == typeof(IntPtr);

老外的代码测试结果:

image

这是妥妥的输给我们了,老外给咱跪了,那些支持简单粗暴实打实的朋友错了。

但是稍等一下,老外的代码里其实有些明显的重复判断,比如在C#中 typeof() 获取的 int 和 Int32 其实是一样的,我们来优化一下这些重复:

return t == typeof(Int16)
|| t == typeof(Int32)
|| t == typeof(Int64)
|| t == typeof(Single)
|| t == typeof(Double)
|| t == typeof(UInt16)
|| t == typeof(UInt32)
|| t == typeof(UInt64)
|| t == typeof(Byte)
|| t == typeof(Decimal)
|| t == typeof(SByte)
|| t == typeof(UIntPtr)
|| t == typeof(IntPtr);

优化版的老外代码测试结果:

image

哈,老外还是跪给我们了。

下面我们再将这个代码改进为使用 TypeCode 方式进行判断,这会提高一些性能。

但是需要注意:

从 Enum 类型中获取到的 TypeCode 会是对应 Int32 类型,这不是我们要的结果,需要额外对其进行判断。

TypeCode 枚举中是没有  IntPtr 和 UIntPtr 项的,所以还是要做额外判断。

改进后的代码:

if (t.IsEnum) return false;var tc = Type.GetTypeCode(t);switch (tc){case TypeCode.Int16:case TypeCode.Int32:case TypeCode.Int64:case TypeCode.Single:case TypeCode.Double:case TypeCode.UInt16:case TypeCode.UInt32:case TypeCode.UInt64:case TypeCode.Byte:case TypeCode.Decimal:case TypeCode.SByte:return true;default:return t == typeof(UIntPtr) || t == typeof(IntPtr);}

老外的代码改进为用 TypeCode 方式进行判断后的测试结果:

image

这个效果就很不错了,一千八百万次的量级,仅仅是比我们的最终代码慢了81毫秒(实测三遍时是稳定地输给我们的代码,不是飘出来的偶然浮动结果),这个性能差距可以忽略了。

这也可以看做是另一个最终版的代码了,因为如果根据你的使用环境来把常用类型放到最前面的话,性能还会更好(尽管你根本感觉不到单次万分之几毫秒的差别),但是不可回避的是对那些我们没有预见到的类型的支持问题,比如这  IntPtr 和 UIntPtr ,在我们前面给出的最终版代码中这两个类型是未做特殊适配就天然支持的。

所以如果你重视优雅度、扩展性和编码知识层级的话,还是建议你使用我前面给出的最终代码。

 

巡回总结报告会演讲

看似非常简单的问题,背后却有这么深的水啊,若没有大家的讨论,断然不会得到这样的成果,并且学到这么多知识。

没有完美的代码,我们期待更好,在此继续讨论吧,也许交流碰撞后还会有更优秀的方案!

(微软:卧槽,看你们这么苦逼,我给你们直接做一个属性出来吧,请期待.Net 框架v10.29博主生日特别无码汉化激情未删减导演剪辑泄露蓝光3D版………嗯,我们将其委托给暴雪工作室开发。)

转载于:https://www.cnblogs.com/SkyD/p/4058486.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545857.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个多月的时间,终于把这件事做完了!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;关注我的小伙伴都知道&#xff0c;前段时间磊哥搞了一个免费的模拟面试&#xff0c;但因为工作和&#xff08;面试&#xff…

漫画:什么是红黑树?(整合版)

前段时间&#xff0c;小灰发布了红黑树相关的文章&#xff0c;分成上下篇来讲解。这一次&#xff0c;小灰把两篇文章做了整合&#xff0c;并且修正了红黑树删除部分的图片错误&#xff0c;感谢大家的指正。————— 第二天 —————————————————二叉查找树&a…

PHP高并发高负载系统架构

2019独角兽企业重金招聘Python工程师标准>>> 一、高并发和高负载的约束条件 硬件部署操作系统Web 服务器PHPMySQL测试二、解决之道——硬件篇 处理能力的提升&#xff1a;部署多颗CPU&#xff0c;选择多核心、具备更高运算频率、更大高速缓存的CPU&#xff1b; 处理…

图解|查找数组中最大值的5种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;我们在一些特定场景下&#xff0c;例如查询公司员工的最高薪资&#xff0c;以及班级的最高成绩又或者是面试中都会遇到查找最…

JDK15正式发布,新增功能预览!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;JDK 15 在 2020 年 9 月 15 号正式发布了&#xff0c;这次发布的主要功能有&#xff1a;JEP 339&#xff1a;EdDSA 数字签名…

[LeetCode] Longest Consecutive Sequence 求解

为什么80%的码农都做不了架构师&#xff1f;>>> 题目 Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, …

双向循环链表

双向循环链表是一种较为特殊的链表&#xff0c;也是一种常见的数据结构&#xff0c;其头尾相连&#xff0c;各节点之间可互相访问&#xff0c;在单链表中&#xff0c;只能依次向后访问&#xff0c;无法访问上一个节点&#xff0c;而双链表可以依次向下访问也可向上访问。 链表…

OkHttp透明压缩,收获性能10倍,外加故障一枚

要使用OkHttp&#xff0c;一定要知道它的透明压缩&#xff0c;否则死都不知道怎么死的&#xff1b;或者活也不知道为什么活的不舒坦。反正不是好事。什么叫透明压缩呢&#xff1f;OkHttp在发送请求的时候&#xff0c;会自动加入gzip请求头Accept-Encoding:gzip。所以&#xff0…

块元素、行内块和内联元素_如何删除内联块元素之间的空间?

块元素、行内块和内联元素Introduction: 介绍&#xff1a; This question has become rather popular. How does one remove whitespaces between the inline-block elements? The interesting thing is there are numerous solutions to this but not all of them are easy …

Spring--quartz中cronExpression 的配置方法

Spring--quartz中cronExpression Java代码 字段 允许值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 日期 1-31 , - * ? / L W C 月份 1-12 或者 JAN-DEC , - * /…

C语言图形库——EasyX基本贴图

在C语言的学习过程中&#xff0c;接触最多的就是黑乎乎的DOS窗口&#xff0c;这也是在消磨学习者的兴趣&#xff0c;学到最后可能还不知道C语言到底能做什么&#xff0c;难道就是输入输出数据吗&#xff1f;当然不是&#xff0c;C的用处很广泛&#xff0c;这里不做讨论。我们能…

一气之下,手撸了一个抖音去水印的工具!

百因必有果说一下我为什么要做个抖音视频去水印工具&#xff0c;其实是因为我的沙雕女友&#xff0c;她居然刚我~有天晚上她在抖音看见一个非常具有 教育意义 的视频&#xff0c;“男人疼媳妇就该承包全部家务活”&#xff0c;然后它就想把视频下载下来&#xff0c;分享到她的姐…

css 隐藏元素 显示元素_使用CSS打印时如何隐藏元素?

css 隐藏元素 显示元素Introduction: 介绍&#xff1a; We have come across many challenges while developing a website or web page and every challenge comes with new learnings. It is a trait of a good developer who develops or creates websites or web pages by…

Java新特性:数据类型可以扔掉了?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在很久很久以前&#xff0c;我们写代码时要慎重的考虑变量的数据类型&#xff0c;比如下面这些&#xff1a;枚举&#xff1a…

Spyder:Python中机器学习的强大武器

So, first of all, you would need to install Anaconda distribution which can be downloaded from the link https://www.anaconda.com/download/ (for Windows users only). 因此&#xff0c;首先&#xff0c;您需要安装Anaconda发行版 &#xff0c;可以从链接https://www.…

对内存重叠的深入认识

内存重叠&#xff1a;拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。在函数strcpy和函数memcpy都没有对内存重叠做处理的&#xff0c;使用这两个函数的时候只有程序员自己保证源地址和目标地址不重叠&#xff0c;或者使用memmove函数进行内存拷…

Android特效 五种Toast具体解释

Toast是Android中用来显示显示信息的一种机制&#xff0c;和Dialog不一样的是&#xff0c;Toast是没有焦点的&#xff0c;并且Toast显示的时间有限&#xff0c;过一定的时间就会自己主动消失。 1.默认效果: 代码:Toast.makeText(getApplicationContext(), "默认Toast样式&…

为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?

△一个对Coding有着独特追求的人△作者 l Hollis来源 l Hollis&#xff08;ID&#xff1a;hollischuang&#xff09;BigDecimal&#xff0c;相信对于很多人来说都不陌生&#xff0c;很多人都知道他的用法&#xff0c;这是一种java.math包中提供的一种可以用来进行精确运算的类型…

动图演示:手撸堆栈的两种实现方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;正式开始之前&#xff0c;先和各位朋友聊聊公众号后期的一些打算&#xff0c;后面的文章计划写一些关于数据结构和算法的内容…

多图带你彻底理解Java中的21种锁!

作者 | 悟空聊架构来源 | 悟空聊架构&#xff08;ID&#xff1a;PassJava666&#xff09;本篇主要内容如下&#xff1a;本篇主要内容本篇文章已收纳到我的Java在线文档、 Github我的SpringCloud实战项目持续更新中帮你总结好的锁&#xff1a;序号锁名称应用1乐观锁CAS2悲观锁sy…