11.3  转换

到目前为止,在需要把一种类型转换为另一种类型时,使用的都是类型转换。而这并不是唯一的方式。

在计算过程中,int可以采用相同的方式隐式转换为long或double,还可以定义所创建的类(隐式或显式)转换为其他类的方式。

为此,可以重载转换运算符,其方式与本章前面重载其他运算符的方式相同。

11.3.1  重载换算运算符

除了重载如上所述的数学运算符之外,还可以定义类型之间的隐式和显式转换。

如果要在不相关的类型之间转换,这是必须的,例如,如果在类型之间没有继承关系,也没有共享接口,这是必须的。

下面定义ConvClass1和ConvClass2之间的隐式转换,即编写下述代码:

ConvClass1 op1 = new ConvClass1();
ConvClass2 op2 = op1;

另外,还可以定义一个显式转换,在下面的代码中调用

 ConvClass1 op3 = new ConvClass1();
ConvClass2 op4 = (ConvClass2)op3;

例如,考虑下面的代码

public class ConvClass1
{
public int val;
public static implicit operator ConvClass2(ConvClass1 op1)//隐式转换
{
ConvClass2 retrunVal = new ConvClass2();
retrunVal.val = op1.val;
return retrunVal;
}
} public class ConvClass2
{
public double val;
public static explicit operator ConvClass1(ConvClass2 op2)//显式转换
{
ConvClass1 returnVal = new ConvClass1();
returnVal.val = (int)op2.val;
return returnVal;
}
}

其中,ConvClass1包含一个int值,ConvClass2包含一个double值。

int值可以隐式转换为double值,所以可以在ConvClass1和ConvClass2之间定义一个隐式转换。

但是反过来就不行了,应把ConvClass2和ConvClass1之间的转换定义为显式转换。

在代码中,用关键字implicit和explicit来指定这些转换,如上所示。对于这些类,下面的代码就很好:

            try
{
ConvClass1 op1 = new ConvClass1();
op1.val = ;
ConvClass2 op2 = op1;
Console.WriteLine(string.Format("op2.val = {0}", op2.val)); ConvClass2 op3 = new ConvClass2();
op3.val = 3e15;
ConvClass1 op4 = (ConvClass1)op3;
Console.WriteLine(string.Format("op4.val = {0}", op4.val));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

在第二个转换中,没有做数据转换的合法性检查,数据会丢失。

本来是3e15但是转换的时候,数据溢出了。超出了int的范围。

解决防范:可以使用checked关键字,进行检查:

 public class ConvClass2
{
public double val;
public static explicit operator ConvClass1(ConvClass2 op2)
{
ConvClass1 returnVal = new ConvClass1();
checked { returnVal.val = (int)op2.val; }
return returnVal;
}
}

如果在显示转换中使用了checked关键字,之前的转换就会产生异常。

13.2    as 运算符

as运算符使用下面的语法,把一种类型转换为指定的引用类型

<operand> as <type>

这只适用于下列情况:

<operand>的类型是<type>类型

<operand>可以隐式转换为<type>类型

<operand>可以封箱到<type>类型中

如果不能从<operand>转换为<type>,则表达式的结果就是null。

注意,基类到派生类的转换可以使用显示转换来进行,但这并不总是有效的。考虑前面示例中的两个类ClassA和ClassD。其中ClassD派生于ClassA:

 interface IMyInterface
{ }
class ClassA : IMyInterface
{ }
class ClassD : ClassA
{ }

以下的代码使用as运算符把obj1中存储的ClassA实例转换为ClassD实例:

ClassA obj1 = new ClassA();
ClassD obj2 = obj1 as ClassD;

则obj2的结果为null

还可以使用多态性把ClassD实例存储在ClassA类型的变量中。下面的代码演示了这个方面,ClassA类型的变量包含ClassD类型的实例,使用as运算符把ClassA类型的变量转换为ClassD类型。

ClassD obj1 = new ClassD();
ClassA obj2 = obj1;
ClassD obj3 = obj2 as ClassD;

其中obj3包含与obj1相同的对象引用,而不是null。

因此,as运算符非常有用,因为下面使用简单类型转换的代码会抛出一个异常:

ClassA obj1 = new ClassA();
ClassD obj2 = (ClassD)obj1;

而as表达式只会把null赋予obj2,不会抛出异常。这表示,下面的代码在C#应用程序中是很常见的

(使用本章前面开发的2个类:Animal和派生于Animal的一个类Cow)

        public void MilkCow(Animal myAnimal)
{
Cow myCow = myAnimal as Cow;
if (myCow != null)
{
myCow.Milk();
}
else
{
Console.WriteLine("{0} isn't a cow,and so can't be milked.", myAnimal.Name);
}
}

这要比检查异常要简单得多!

最新文章

  1. 职工工资管理系统 --C语言
  2. 认识Service
  3. 对《[Unity官方实例教程 秘密行动] Unity官方教程《秘密行动》(十二) 角色移动》的一些笔记和个人补充,解决角色在地形上移动时穿透问题。
  4. MATLAB的基本元素
  5. java 迭代器iterator
  6. 用UNetbootin来安装USB LINUX,好像比ULTRA ISO省事
  7. JavaSE_ 面向对象 总目录(7~10)
  8. BZOJ 1602: [Usaco2008 Oct]牧场行走( 最短路 )
  9. 来看看CBIS 2017中国(上海)大数据产业创新峰会有哪些大师出席
  10. druid查询
  11. postgresql如何让主键自增
  12. ZT: C#不建类直接Json解析与取值
  13. Spring整合quartz关闭,关闭Tomcat Servlet容器时内存泄漏
  14. hdu 1263 水果 【二维map】
  15. HTTP1.1协议-RFC2616-中文版
  16. ORA-01031: insufficient privileges 错误解决
  17. mac 常用开发软件列表
  18. spark streaming 概述
  19. vue如何实现代码打包分离(按需加载)
  20. 2017秋-软件工程第十二次作业(一)-PSP总结

热门文章

  1. JavaScript之arguments对象讲解
  2. Topcoder 多校T-shirt场
  3. H5时代的新存储简介
  4. 【剑指offer】题目38 数字在排序数组中出现的次数
  5. 视频转换工具 Transmageddon
  6. CRM-性能测试报告
  7. Win32应用程序中文支持
  8. C Primer Plus之结构和其他数据形式
  9. pycharm控制台中文乱码问题
  10. js中几个正则表达式相关函数使用时g标志的作用