本篇体验引用类型转换:子类转换成父类,父类转换成子类,以及不是子父级关系类之间的转换。

□ 隐式转换:子类转换成父类

    public class Animal
    {
        public int _age;

        public Animal(int age)
        {
            this._age = age;
        }
    }

    public class Dog : Animal
    {
        public float _weight;

        public Dog(float weight, int age) : base(age)
        {
            _weight = weight;
        }
    }

客户端,子类转换成父类。

        static void Main(string[] args)
        {
            Dog dog = new Dog(2.5f,12);
            Animal animal = dog;
            Console.WriteLine(animal._age);
        }

结果:12

可见,子类转换成了父类是隐式转换。这种转换在栈上完成,栈上先有代表子类的变量dog,然后有代表父类的变量animal,最后把dog保存的堆地址赋值给了anmial。

□ 强转:父类转换成子类

如果客户端父类转换成子类。

        static void Main(string[] args)
        {
            Animal animal = new Animal(12);
            Dog dog = (Dog)animal;
            Dog dog = animal as Dog;
            if (dog != null)
            {
                Console.WriteLine(dog._age);
            }
            else
            {
                Console.WriteLine("转换失败");
            }
        }

结果:抛出异常,Animal无法转换成Dog

可见,使用以上方式把父类强转成子类,转换失败会抛出异常。

□ 使用as强转:父类转换成子类

如果客户端使用as把父类转换成子类。

        static void Main(string[] args)
        {
            Animal animal = new Animal(12);
            Dog dog = animal as Dog;
            if (dog != null)
            {
                Console.WriteLine(dog._age);
            }
            else
            {
                Console.WriteLine("转换失败");
            }
        }

结果:转换失败

可见,使用as把父类强转成子类,转换失败不会抛出异常。

□ 使用is先判断再强转:父类转换成子类

可以在强转之前,先使用is判断父类是否能转换成子类,再根据子类实例是否为null判断是否转换成功。

        static void Main(string[] args)
        {

            Animal animal = new Animal(12);
            Dog dog = null;
            if (animal is Dog)
            {
                dog = (Dog)animal;
            }
            if (dog == null)
            {
                Console.WriteLine("转换失败");
            }
            else
            {
                Console.WriteLine("转换成功");
            }
        }

□ 使用操作符实现强转

可以在一个类中设计一个静态的、隐式的、操作符方法,把本类实例转换成另外一个目标转换对象实例。

    public class Benz
    {
        public int Mile { get; set; }

        public Benz(int mile)
        {
            Mile = mile;
        }

        public static implicit operator Car(Benz benz)
        {
            return new Car(){Mile = benz.Mile};
        }
    }

    public class Car
    {
        public int Mile { get; set; }
    }

客户端

        static void Main(string[] args)
        {
            Benz benz = new Benz(1000);
            Car car = benz;
            Console.WriteLine(car.Mile);
            Console.ReadKey();
        }

结果:1000

○ 使用操作符,把原本毫无关系的2个类建立关系,可实现转换
○ 当执行Car car = benz的时候,就会执行Benz类的操作符方法operator Car
○ 操作符方法必须满足几个条件:静态的、implicit,名称和需要转换的类名保持一致,返回需要转换的类实例
○ 当执行Car car = benz的时候,在堆上创建一个Car实例,然后赋值给栈上的变量car

总结:
○ 子类转换成父类是隐式转换,其本质是栈上的一个变量值赋值给了栈上另外一个变量
○ 父类转换成子类,如果直接使用"(子类)父类实例"的方式,很容易抛出异常
○ 父类转换成子类,如果使用as,可以避免抛出异常
○ 父类转换成之类,也可以先使用is判断,然后再进行转换
○ 2个不是子父级关系的类,可以在1个类中设计一个操作符方法,把该类实例转换成目标对象实例

C#引用类型转换的几种方式的更多相关文章

  1. PHP中数据类型转换的三种方式

    PHP中数据类型转换的三种方式 PHP的数据类型转换属于强制转换,允许转换的PHP数据类型有: 1.(int).(integer):转换成整形2.(float).(double).(real):转换成 ...

  2. 传递引用类型参数的两种方式(转自 MSDN)

    引用类型的变量不直接包含其数据:它包含的是对其数据的引用.当通过值传递引用类型的参数时,有可能更改引用所指向的数据,如某类成员的值(更改属性的值),但是无法更改引用本身的值:也就是说,不能使用相同的引 ...

  3. PHP判断变量类型和类型转换的三种方式

    前言: PHP 在变量定义中不需要(不支持)明确的类型定义.变量类型是根据使用该变量的上下文所决定的.所以,在面对页码跳转.数值计算等严格的格式需求时,就要对变量进行类型转换. 举例如下: $foo ...

  4. vue项目中引用echarts的几种方式

    准备工作: 首先我们初始化一个vue项目,执行vue init webpack echart,接着我们进入初始化的项目下.安装echarts, npm install echarts -S //或   ...

  5. int类型转换的几种方式差异

    1.(int)是一种类型转换:当我们觟nt类型到long,float,double,decimal类型,可以使用隐式转换,但是当我们从long类型到int类型就需要使用显式转换,否则会产生编译错误. ...

  6. 数据类型转换的三种方式 Convert,parse和TryParse的解析

    以Int类型为例,具体说明Convert.ToInt32(object value),int.Parse(object value)和int.TryParse(string s,out int res ...

  7. Vue 引用图片的三种方式

    首先给图片地址绑定变量 <template> <img :src="imgUrl"> </template> 在script中设置变量 < ...

  8. Java引用类型转换

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

  9. c语言 函数传输传递的三种方式(值、指针、引用)

    本文摘自<彻底搞定c指针> 一.三道考题开讲之前,我先请你做三道题目.(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?)考题一,程序代码如下:void Exchg1(int x, in ...

随机推荐

  1. C++之可调用对象

    C++中的可调用对象分为以下几种: 函数 函数指针 lambda表达式 bind创建的对象 重载了函数调用运算符(即“()”)的类 函数.函数指针不再介绍.lambda表达式与bind创建的类参考—— ...

  2. MySql数据库 主从复制/共享 报错

    从 获取不到 共享主的数据, 错误信息: Waiting for master to send event 解决方案: // 1. 从V表获取PrNo的数据 select * from Vendor_ ...

  3. Kafka ACL使用实战(单机版)

    一.简介 自0.9.0.0.版本引入Security之后,Kafka一直在完善security的功能.当前Kafka security主要包含3大功能:认证(authentication).信道加密( ...

  4. C#连接mariadb代码及方式

    不负责任的说MariaDb和MySQL很多都是通用的,因为来自同一个爹... 和MySQL连接方式差不多 首先配置好你的MariaDb,创建test数据库,在test里创建MyTable表,脚本如下( ...

  5. HBase(九)HBase表以及Rowkey的设计

    一 命名空间 1 命名空间的结构 1) Table:表,所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定, 则在 default 默认的命名空间中. 2) RegionServer g ...

  6. 基于范围的for循环

    语法: for ( for-range-declaration : expression ) statement 注意一般用auto表达类型.不需要修改时常用引用类型 例子: // range-bas ...

  7. 【LOJ】#2541. 「PKUWC2018」猎人杀

    题解 一道神仙的题>< 我们毙掉一个人后总的w的和会减少,怎么看怎么像指数算法 然而,我们可以容斥-- 设\(\sum_{i = 1}^{n} w_{i} = Sum\) 我们把问题转化一 ...

  8. USACO 5.5 Twofive

    TwofiveIOI 2001 In order to teach her young calvess the order of the letters in the alphabet, Bessie ...

  9. Spring的配置文件ApplicationContext.xml配置头文件解析

    Spring的配置文件ApplicationContext.xml配置头文件解析 原创 2016年12月16日 14:22:43 标签: spring配置文件 5446 spring中的applica ...

  10. PHP问题解决

    1.PHP在上传文件的时候出现错误Internal Server Error Internal Server ErrorThe server encountered an internal error ...