在C#中,当引用类型需要转换的时候,经常会用到关键字is、as以及显式强转。本篇来体验这三者的用法。

先来梳理.NET引用类型转换的"约定俗成",或者叫"惯例":
● 子类可以隐式转换为父类/基类,也就是"里氏替换原则"所说的:子类必须能够替换其父类/基类。
● 父类/基类转换为子类时,必须进行显式类型强转。

子类转换成父类

class Program
{
static void Main(string[] args)
{
Animal animal = new Dog(){Name = "Dog",Age = 1};
Console.WriteLine(animal.Name);
Console.ReadKey();
}
} public class Animal
{
public string Name { get; set; }
} public class Dog : Animal
{
public int Age { get; set; }
}

输出结果:Dog

以上,体验了子类转换成父类,从中可以看出:子类Dog确实能替换父类Animal,换句话说,子类就是父类,子类的实例可以赋值给父类的变量,不需要as,不需要强转,一切都是隐式发生,很好地体现了"里氏替换原则"。

父类转换为子类,父类变量通过子类赋值而创建

父类as成子类:

Animal animal = new Dog(){Name = "Dog",Age = 1};
Dog dog = animal as Dog;
Console.WriteLine(dog.Name + " " + dog.Age);
Console.ReadKey();

输出结果:Dog 1

父类显式强转成子类

Animal animal = new Dog(){Name = "Dog",Age = 1};
Dog dog = (Dog)animal;
Console.WriteLine(dog.Name + " " + dog.Age);
Console.ReadKey();

输出结果:Dog 1

以上,不管是使用as还是显式强转,父类都可以转换成子类,但是有前提的:把子类实例赋值给父类变量。

父类转换为子类,父类变量通过自身构造函数而创建

父类as成子类失败:

Animal animal = new Animal(){Name = "Sheep"};
Dog dog = animal as Dog;
Console.WriteLine(dog.Name + " " + dog.Age);
Console.ReadKey();

输出结果:报"NullReferenceException"错

可见,当父类变量通过自身构造函数而创建时,无法将父类转换成子类。

(1)为了避免as的时候报"NullReferenceException"错,引入关键is做类型判断:

Animal animal = new Animal(){Name = "Sheep"};
if (animal is Dog)
{
Dog dog = animal as Dog;
Console.WriteLine(dog.Name + " " + dog.Age);
}
else
{
Console.WriteLine("animal不能转换为Dog");
}
Console.ReadKey();

输出结果:animal不能转换为Dog

(2)用as做类型转换的时候,如果转换失败,返回null。根据这点,也可以通过判断as转换后的返回值是否为null,来避免报错:

Animal animal = new Animal(){Name = "Sheep"};
Dog dog = animal as Dog;
if (dog != null)
{
Console.WriteLine(dog.Name + " " + dog.Age);
}
else
{
Console.WriteLine("animal不能转换为Dog");
}
Console.ReadKey();

输出结果:animal不能转换为Dog

父类显式强转成子类失败

Animal animal = new Animal(){Name = "Sheep"};
Dog dog = (Dog) animal;
Console.WriteLine(dog.Name + " " + dog.Age);
Console.ReadKey();

输出结果:报"InvalidCastException"错

可见,当父类变量通过自身构造函数而创建时,无法将父类转换成子类。

为了避免显示强转时报"InvalidCastException"错,引入关键字is做类型判断:

Animal animal = new Animal(){Name = "Sheep"};
if (animal is Dog)
{
Dog dog = (Dog)animal;
Console.WriteLine(dog.Name + " " + dog.Age);
}
else
{
Console.WriteLine("animal不能转换为Dog");
}
Console.ReadKey();

输出结果:animal不能转换为Dog

总结

● 对于引用类型的转换,应该考虑使用显式强转或as。两者的区别在于:一旦类型无法转换,使用显式强转会报错,而使用as会返回null。
● 为了避免显式强转或as所引发的报错,应该考虑使用is来判断类型间是否能转换。
● 使用as进行引用类型转换,不仅可以用is来判断类型间是否能转换,还可以通过判断as后的返回值是否为null,然后采取相应的操作。
● 对于基本类型的转换:使用Convert, Parse, TryParse等。

is用于判断类型是否一致,as和显式强转用于类型的转换。

C#引用类型转换,到底使用is,as还是显式强转?的更多相关文章

  1. Java引用类型转换

    java的引用类型转换分为两种: 向上类型转换,是小类型到大类型的转换 向下类型转换,是大类型到小类型的转换 现存在一个Animal动物类,猫子类和狗子类继承于Animal父类: 1 public c ...

  2. C#引用类型转换的几种方式

    本篇体验引用类型转换:子类转换成父类,父类转换成子类,以及不是子父级关系类之间的转换. □ 隐式转换:子类转换成父类 public class Animal { public int _age; pu ...

  3. Java学习笔记二十六:Java多态中的引用类型转换

    Java多态中的引用类型转换 引用类型转换: 1.向上类型转换(隐式/自动类型转换),是小类型到大类型的转换: 2.向下类型转换(强制类型转换),是大类型到小类型的转换: 3.instanceof运算 ...

  4. Day06_28_Instanceof关键字 和 引用类型转换

    Instanceof关键字 和 引用类型转换 Instanceof 关键字 - instanceof 是 Java 的保留关键字.它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean ...

  5. C++进阶--显式类型转换(casting)

    //############################################################################ /* * 显式类型转换 * * 类型转换 ...

  6. C++显式类型转换

    C++显式类型转换 (注:本文例程改编自<C++ Primer>) 关于类型转换,C++保留了C语言中的类型转换方式,并提供了4中新的类型转换方式.<Effective C++> ...

  7. c# implicit explicit关键字(隐式和显式数据类型转换)

    implicit关键字用于声明隐式的用户定义类型转换运算符.(explicit反之)explicit则用于显示转换用户自定义类型.static implicit operator target_typ ...

  8. JavaScript 数据类型转换(显式与隐式)

    一.数据类型 JS中有5中简单数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number.String.还有一种复杂数据类型------Object,Object本质是 ...

  9. Golang 类型转换,断言和显式强制转换

    1 前言 类型转换,可以用断言(只能使用在interface{}类型转换成其它类型)和显式类型强制转换(常规是用于基本类型) 2 代码 //graphql-go func(params graphql ...

随机推荐

  1. java 添加一组元素

    在java包中的Arrays和Collection类中都有很多实用方法,可以在一个Collection中添加一组元素,Array.asList()方法接受一个数组或是一个用逗号分隔的元素列表(使用可变 ...

  2. Centos之目录处理命令

    linux中 关于目录 有几个重要概念 一个是 / 根目录  还有一个当前用户的家目录 比如 root用户的家目录是 /root  普通用户的家目录是/home/xxx 下 root登录 默认家目录 ...

  3. MS Sql Server 数据库或表修复(DBCC CHECKDB)

    MS Sql Server 提供了很多数据库修复的命令,当数据库质疑或是有的无法完成读取时可以尝试这些修复命令.  1. DBCC CHECKDB  重启服务器后,在没有进行任何操作的情况下,在SQL ...

  4. Linux学习笔记:cat、tac、more、less、head、tail查看文件内容

    Linux下查看文件内容可以通过以下命令: cat tac more less head tail nl tailf 1.cat 由第一行开始显示内容,并将所有内容输出.当文件过大时,使用cat查看不 ...

  5. iOS图片缓存

    iOS的内存管理始终是开发者面临的大问题,内存占用过大时,很容易会被系统kill掉,开发者需要尽可能的优化内存占用问题. 现在的App界面做的越来越精致,里面集成了大量的图片,笔者首先想到的就是如何减 ...

  6. JAVA类课后练习

    1.Pg168--2 package com.hanqi; import java.util.Scanner; public class Rectangle { Rectangle() { //完成初 ...

  7. asp.net MVC发布iis无法加载css,js和图片

    今天真够郁闷的,遇到了在本地能运行的项目到了iis服务器那里就不行了,无法加载css,js和图片,这里说清楚一下先,关于asp.net 的MVC中这样的情况其实不少,但是之前遇到的是在visual s ...

  8. CentOS7.5安装cairo-dock,比mac托盘还美

    1.下载安装nux-desktop 到http://li.nux.ro/download/nux/dextop/el7/x86_64/找到nux-dextop-release-xxxx.nux.noa ...

  9. bzoj 1218: [HNOI2003]激光炸弹

    思路:二维前缀和, 枚举矩形左上端点. #include<bits/stdc++.h> #define LL long long #define fi first #define se s ...

  10. jenkins发邮件问题

    1.发送邮件不成功 Sending e-mails to: *******@**.cn    Finished: FAILURE 解决办法     jenkins-->configure glo ...