在 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少用强制类型转换的更多相关文章

  1. C++强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast

    1. c强制转换与c++强制转换 c语言强制类型转换主要用于基础的数据类型间的转换,语法为: (type-id)expression//转换格式1 type-id(expression)//转换格式2 ...

  2. Javascript对象Oject的强制类型转换

    众所周知Javascript作为一种动态类型,弱类型的脚本语言其数据类型在很多时候都会发生类型转换.而这些类型转换往往都是隐式的,这让我们在使用Js的时候会产生许多麻烦.而Js的基础数据类型的转换在此 ...

  3. el 表达式 强制类型转换

    el 表达式 强制类型转换 今天有人问我了这个问题 jsp页面中,能否实现 <%  request.setAttrites("a","1234");  % ...

  4. c#小灶——自动类型转换和强制类型转换

    前面已经认识了不同的数据类型,你们有没有尝试过让不同的数据类型进行运算呢? ; double b = a; Console.WriteLine(b); 运行结果是:1 我们把一个整型的变量赋值给了一个 ...

  5. [转载]C++中四种强制类型转换方式

    C++中四种强制类型转换方式 原文地址:http://www.cnblogs.com/home123/p/6763967.html 类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单( ...

  6. java中强制类型转换

    在Java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...

  7. C++强制类型转换

    C语言强制类型转换过于粗暴,任意类型之间都可以进行转换,编译很难判断其正确性; 难于定位,在源码中无法快速定位所有使用强制类型转换的语句. C++将强制类型转换分为4种不同的类型:static_cas ...

  8. java提高篇(十一)-----强制类型转换

    在java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...

  9. JavaScript学习10 JS数据类型、强制类型转换和对象属性

    JavaScript学习10 JS数据类型.强制类型转换和对象属性 JavaScript数据类型 JavaScript中有五种原始数据类型:Undefined.Null.Boolean.Number以 ...

随机推荐

  1. ACM北大暑期课培训第八天

    今天学了有流量下界的网络最大流,最小费用最大流,计算几何. 有流量下界的网络最大流 如果流网络中每条边e对应两个数字B(e)和C(e), 分别表示该边上的流量至少要是B(e),最多 C(e),那么,在 ...

  2. 低副瓣阵列天线综合2 matlab HFSS

    接着继续研究阵列天线设计,得到了电流幅度分布或功率分布之后,就可以进行阵列设计或馈电网络设计了,之前利用HFSS仿真过单列的串馈天线,后面会继续复习熟悉一下,本次我找了一篇硕士论文利用威尔金森功分器来 ...

  3. Qt Installer Framework翻译(2)

    开始 Qt IFW作为Qt项目的一部分进行开发.该框架自身也使用Qt.然而,它能被用于安装所有类型的应用程序,包括(但不限于)使用Qt编译的. 支持的平台 已在下列平台中进行了测试: > Mic ...

  4. orcle 创建用户的几个步骤

    创建用户一般分四步: 第一步:创建临时表空间 第二步:创建数据表空间 第三步:创建用户并制定表空间 第四步:给用户授予权限1.创建临时表空间 create temporary tablespace t ...

  5. 简单理解设计模式——享元模式-线程池-任务(tesk)

    前面在写到多线程的文章的时候,一直想写一篇关于线程池等一系列的文章,做一下记录,本篇博客记录一下设计模式中享元模式的设计思想,以及使用享元模式的实现案例——线程池,以及线程池的简化版——任务(tesk ...

  6. HGE_improve 0.1发布

    HGE_improve 0.1发布 写了1个月了,虽然还有很多很多缺陷,但丑姑娘也是要见公婆的. 主要修改如下: 1.全UNICODE化 2.增加切片动画 3.增加骨骼动画 4.增加MyGUI接口 5 ...

  7. SpringBoot实现简单的CRUD

    CRUD-员工列表 实验要求: 1).RestfulCRUD:CRUD满足Rest风格: URI: /资源名称/资源标识 HTTP请求方式区分对资源CRUD操作 2).实验的请求架构; 3).员工列表 ...

  8. 个人第四次作业--Alpha项目测试

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/GeographicInformationScience 这个作业要求在哪里 https://www.cn ...

  9. RainbowPlan-Alpha版本发布2

    博客介绍 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/GeographicInformationScience/ 这个作业要求在哪里 https:// ...

  10. spring动态修改bean

    spring动态修改bean @RequestMapping("ok") public Object test2(){ ApplicationContext application ...