在 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. Longhorn入门级教程!轻松实现持久化存储!

    介 绍 在本文中你将学会如何使用k3s在Civo上运行Longhorn.如果你还没使用过Civo,可以到官网注册(https://www.civo.com/ )还可以申请免费的使用额度.首先,需要一个 ...

  2. 悄摸直播(二)—— 播流器实现(拉取rtmp服务器中的数据流,播放直播画面)

    悄摸直播 -- JavaCV实现本机摄像头画面远程直播 播流器 一.功能说明 从rtmp服务器中获取视频流数据 + 展示直播画面 二.代码实现 /** * 播流器 * @param inputPath ...

  3. Rust入坑指南:海纳百川

    今天来聊Rust中两个重要的概念:泛型和trait.很多编程语言都支持泛型,Rust也不例外,相信大家对泛型也都比较熟悉,它可以表示任意一种数据类型.trait同样不是Rust所特有的特性,它借鉴于H ...

  4. 写了个 Task.WhenAll(t)的一个例子。

    public static void Main() { var t = Task.Run(() => { throw new Exception("aa"); }); Tas ...

  5. [C++]最小生成树

    1. 最小生成树定义 树是指没有环路的图,生成树就是指一个图上面删除一些边,使它没有环路. 最小生成树就是指生成树中边权之和最小的那一种. 上图的最小生成树就是这样: 2. Prim 算法 2.1. ...

  6. make_safe

    from django.utils.safestring import mark_safe mark_safe('<input type="checkbox" id=&quo ...

  7. 异数OS谈发展国产操作系统的问题

    异数OS谈发展国产操作系统的问题 为什么写本文 最近中兴被美制裁的问题以及红芯使用开源技术宣称国产自主技术引发了舆论不少对国产CPU以及国产操作系统自主技术的讨论,为什么我们国家有BAT,有原子弹,能 ...

  8. PHPStorm 最新版下载

    2019最新版phpstorm   包含其他版下载地址   https://www.jetbrains.com/phpstorm/download/other.html

  9. 机器学习环境配置系列六之jupyter notebook远程访问

    jupyter运行后只能在本机运行,如果部署在服务器上,大家都希望可以远程录入地址进行访问,这篇文章就是解决这个远程访问的问题.几个基本的命令就可以搞定,然后就可以愉快的玩耍了. 1.安装jupyte ...

  10. 废旧手机改造之给你的手机安装win10系统

    最近又开始琢磨把我这个即将退出的二手手机再利用一下 发现了一个不错的软件 先上图 是不是感觉逼格很高啊 点击下面链接即可下载使用 https://www.lanzous.com/i4gpsib 欢迎交 ...