多用as少用强制类型转换
在 C# 中存在一个名叫静态类型检查的机制,这个机制可以让编译器帮助我们把类型不服的用法找出来,从而使得应用程序在运行期间加少一些类型检查的操作。但是有时候我们还是需要进行运行期类型检查,比如我们在设计框架时将方法的参数类型定义为 object ,那么这时我们就有很大的可能需要将 object 类型的参数先转换为其他类型。我们进行转换时会有两种方法可以使用:一种是强制类型转换,这种方法可以绕过编译器的类型检查,另一种是先通过 is 判断操作是否合理,是否可以转换,然后再使用 as 运算符进行转换,或者使用强制类型转换。下面我们就来讲解一下为什么多使用 as 少使用强制类型转换。
零、as and is
使用 as 进行类型转换会比强制类型转换更加安全,而且运行时效率更高。但是这里有一点需要注意的是 as 和 is 运算符不会考虑用户所定义的类型转换,只有当运行期的类型与要转换到的类型相符时才能顺利进行。一般来说 as 类型转换很少会出现为了类型转换而创建新的对象,只有在 as 运算符把装箱值类型转换未装箱且可以为 null 的类型时才会创建新对象。
is 运算符遵循多态原则,也就是说例如 变量 Husky(哈士奇)是 Dog 类型,并且 Dog 类型继承自 Animal 类型,那么 代码段 husky is Animal 返回值就是 True 。因此我们可以利用这一特性来判断某个对象是否是某个具体类型。当然我们也可用通过 GetType 方法来查询对象的运行期类型,这样可以使开发人员写出比 as 和 is 更加具体更加详细的类型,这主要归功于它所返回的对象类型能够和某种特定类型进行对比。
一、为什么不用强制类型转换
我们先来看一段代码:
try
{
object obj = Factory.GetObject();
Animal animal;
animal = (Animal) obj;
if (animal !=null)
{
// more code
}
// more code
}
catch (InvalidCastExcept ex)
{
// more code
}
在上述代码中我们使用了强制类型转换将 object 类型的变量转换为 Animal 类型,我相信部分开发人员在实际开发中都会这么写,这么些也不为过,但是这其中存在一个问题,开发人员需要处理两个问题。首先程序如果无法将变量 obj 转换为 Animal 类型将抛出 InvalidCastException 异常,因此我们必须捕获,其次在强制类型转换时遇到 null 的时候并不会抛出异常,因此我们还要判断变量 animal 是否为 null 。既然强制类型转换有这个问题,那我们该如何解决呢?这时我们就可以用到 as 和 is 运算符了,同样我们先看一下代码:
try
{
object obj = Factory.GetObject();
if (obj is Animal)
{
Animal animal = obj as Animal;
// more code
}
else
{
// more code
}
}
利用这种方法我们首先判断 obj 是否可以转换为 Animal 类型,如果可以就利用 as 运算符来转换,反之执行其他代码。既不需要捕获错误,也不需要强制转换,减少了代码量同时也减少了代码出错的机率。
as 运算符和强制类型转之间有一个很大的区别,那就是如何对待用户自定义的转换逻辑。 as 和 is 运算符除了必须进行的装箱和拆箱外,它不会执行其他任何操作,也就是说 as 和 is 只会判断带转换对象在运行期是什么类型,并根据结果进行相应的处理。那么如果带转换对象既不属于目标类型也不属于目标类型所派生出来的类型的话, as 操作就宣告失败。强制类型转换则不然,它有可能使用一些类型的转换逻辑进行类型转换,而且不仅仅是用户自定义的转换逻辑,还包含了内置类型之间的转换。但是要注意的是强制类型转换可以会造成信息丢失,例如从 long 强制转换为 short 。
在某些情况下利用强制类型转换从代码上来看似乎可以转换成功,但实际上却转换不成功。这时为什么呢?虽然强制类型转换会把用户自定义的转换逻辑考虑进去,但是它只针对对象的编译期类型,编译期类型并不是是基类型。例如带转换类型在编译期是 object 类型,因此编译器会将它看作 object ,这时如果进行强制类型转换的话就会报错。
前面说了那么多使用 as 的好处,那么在这一小节里我们就来说说在什么时候不能使用 as 和 is 。同样,先来看一小段代码:
object obj =Factory.GetValue();
int num = obj as int;
上面的这段代码运行起来后将会报错,为什么呢?这是因为当 obj 不是 int 类型时返回的值是 null ,但是 int 类型无法接受 null 值。因此当指定类型不可接受 null 值时 as 无法进行类型转换。
二、一个问题
下面我们再思考一个问题,我们都知道 foreach 所针对的序列是非泛型序列它会在迭代过程中自动转换,那么 foreach 的类型转换使用的是 as 呢还是强制类型转换呢?
foreach 使用的时强制类型转换,会把对象从 object 类型转换成循环体所需要的类型,之所以使用强制类型转换是因为 foreach 需要同时应对值类型和引用类型。
三、总结
在开发中我们应该尽量避免使用强制类型转换,强制类型转换在某些情况下可能会出现开发人员预料之外的结果,使用 as 和 is 运算符可以确保对象确实可以进行类型转换时才给出答案,这样可以保证程序的正确性。
本文由博客一文多发平台 OpenWrite 发布!更多文章扫码关注“喵叔呦”
多用as少用强制类型转换的更多相关文章
- C++强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast
1. c强制转换与c++强制转换 c语言强制类型转换主要用于基础的数据类型间的转换,语法为: (type-id)expression//转换格式1 type-id(expression)//转换格式2 ...
- Javascript对象Oject的强制类型转换
众所周知Javascript作为一种动态类型,弱类型的脚本语言其数据类型在很多时候都会发生类型转换.而这些类型转换往往都是隐式的,这让我们在使用Js的时候会产生许多麻烦.而Js的基础数据类型的转换在此 ...
- el 表达式 强制类型转换
el 表达式 强制类型转换 今天有人问我了这个问题 jsp页面中,能否实现 <% request.setAttrites("a","1234"); % ...
- c#小灶——自动类型转换和强制类型转换
前面已经认识了不同的数据类型,你们有没有尝试过让不同的数据类型进行运算呢? ; double b = a; Console.WriteLine(b); 运行结果是:1 我们把一个整型的变量赋值给了一个 ...
- [转载]C++中四种强制类型转换方式
C++中四种强制类型转换方式 原文地址:http://www.cnblogs.com/home123/p/6763967.html 类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单( ...
- java中强制类型转换
在Java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...
- C++强制类型转换
C语言强制类型转换过于粗暴,任意类型之间都可以进行转换,编译很难判断其正确性; 难于定位,在源码中无法快速定位所有使用强制类型转换的语句. C++将强制类型转换分为4种不同的类型:static_cas ...
- java提高篇(十一)-----强制类型转换
在java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...
- JavaScript学习10 JS数据类型、强制类型转换和对象属性
JavaScript学习10 JS数据类型.强制类型转换和对象属性 JavaScript数据类型 JavaScript中有五种原始数据类型:Undefined.Null.Boolean.Number以 ...
随机推荐
- 2013 ACM/ICPC Asia Regional Online —— Warmup2 ABEGKL
HDU4716 A. A Computer Graphics Problem A题目描述 题意:输出手机剩余电量,保证给出的数是10的倍数. 题解:水题,按题意输出即可. 代码: #include & ...
- 比特币学习笔记(一)---在windows下编译搭建比特币环境
最近打算研究下比特币源码,却发现这套源码正常情况下得在linux下编译运行,而我的机器是windows的. 怎么办呢? 起初打算用mingw和cygwin搞搞看,试了许久后发现行不通,必须转到linu ...
- JWT (一):认识 JSON Web Token
JWT(一):认识 JSON WebToken JWT(二):使用 Java 实现 JWT 什么是 JWT? JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑 ...
- vue 项目中运用到的插件 或者依赖安装
1.安装less ,less-load npm install less less-loader --save-dev 2.安装vux npm install vux --save npm insta ...
- 【转】SQL语句面试题
1.一道SQL语句面试题,关于group by表内容:2005-05-09 胜2005-05-09 胜2005-05-09 负2005-05-09 负2005-05-10 胜2005-05-10 负2 ...
- 本地缓存google.guava及分布式缓存redis 随笔
近期项目用到了缓存,我选用的是主流的google.guava作本地缓存,redis作分布式 缓存,先说说我对本地缓存和分布式缓存的理解吧,可能不太成熟的地方,大家指出,一起 学习.本地缓存的特点是速度 ...
- javaweb-codereview 学习记录-1
Servlet是在Java Web容器上运行的小程序,通常我们用Servlet来处理一些较为复杂的服务器端的业务逻辑.值得注意的是在Servlet3.0之后(Tomcat7+)可以使用注解方式配置Se ...
- [ Python入门教程 ] Python中日志记录模块logging使用实例
python中的logging模块用于记录日志.用户可以根据程序实现需要自定义日志输出位置.日志级别以及日志格式. 将日志内容输出到屏幕 一个最简单的logging模块使用样例,直接打印显示日志内容到 ...
- 《Kubernetes权威指南》01_Kubernetes入门——Kubernetes 是什么
01_Kubernetes入门 li {list-style-type:decimal;}.wiz-editor-body ol.wiz-list-level2 > li {list-style ...
- devops与CICD
前言 devops的概念已经在前一章已经说过了,下面介绍CICD的概念. CI(Continuous Integration,持续集成) 持续集成中,开发人员将会频繁地向主干提交代码,这些新提交的代码 ...
