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);
}
}

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

C#中的转换的更多相关文章

  1. SQL Server中行列转换 Pivot UnPivot

    SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...

  2. awk中分隔符转换

    awk中分隔符转换的问题(转) 在awk中明明用OFS重新设置了分隔符,为什么在输出的时候还是原样输出呢! 他是这么写的:    echo 1,2,3,4 | awk 'BEGIN{FS=" ...

  3. kettle删除资源库中的转换或者作业

    在资源库中新建转换,作业都很简单,那么加入现在不需要其中某个转换或者作业该怎么办呢? 下图是已经存在的转换跟作业 现在需要删除aa这个转换 操作步骤如下: 1.工具----资源库----探索资源库 出 ...

  4. Java中String转换Double类型 Java小数点后留两位

    Java中String转换Double类型 double num1 = 0.0; String qq = "19.987"; num1 = Double.valueOf(qq.to ...

  5. VSTO中Word转换Range为Image的方法

    VSTO中Word转换Range为Image的方法 前言 VSTO是一套用于创建自定义Office应用程序的Visual Studio工具包,通过Interop提供的增强Office对象,可以对Wor ...

  6. js中时间戳转换成时间格式

    js中时间戳转换成时间格式, // 时间戳转换成时间格式 var formatDate = function(date){ date = new Date(date); var y=date.getF ...

  7. QT国际化(中英转换)

    转载:https://blog.csdn.net/u012528526/article/details/54707233 QT国际化(中英转换) 我们都知道在安卓中,想做国际化很简单,只需要建立对应的 ...

  8. AS3中String转换成Boolean

    AS3中, 对布尔值的转换, 规定所有的非空字符串都是true. 下面都不行: var f:Boolean = new Boolean(str); var f:Boolean = str as Boo ...

  9. SQL中DateTime转换成Varchar样式

    SQL中DateTime转换成Varchar样式语句及查询结果:Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSelect ...

  10. VC++使用CImage在内存中Bmp转换Jpeg图片

    之前写了一篇<VC++使用CImage在内存中Jpeg转换Bmp图片>,通过CImage实现了在内存中Jpeg转Bmp. 既然Jpeg能转Bmp,那CImage也支持Bmp转Jpeg,与上 ...

随机推荐

  1. 机器学习&&数据挖掘之一:决策树基础认识

    决策树入门篇 前言:分类是数据挖掘中的主要分析手段,其任务就是对数据集进行学习并构造一个拥有预测功能的分类模型,用于预测未知样本的类标号,把类标号未知的样本按照某一规则映射到预先给定的类标号中. 分类 ...

  2. 【BZOJ】【1067】 【SCOI2007】降雨量

    思路题 玛雅,这分类讨论快讨论地疯了…… 从huzecong神的题解那里得到的灵感…… 首先考虑最好确定的情况:为true的时候,此时必须同时满足 1.x和y这两年的降雨量已知,且rain[x]< ...

  3. 剑指offer--3题

    题目:输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). 例如输入的数组为1, -2, 3, ...

  4. 【bzoj1007】[HNOI2008]水平可见直线

    1007: [HNOI2008]水平可见直线 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5932  Solved: 2254[Submit][Sta ...

  5. wireshark常用的过滤命令

    我们使用wireshark抓包,却不知道如何分析这些包,也无法从海量的包中提取自己需要的数据,下面简单介绍下wireshark的过滤规则. 过滤源ip.目的ip.在wireshark的过滤规则框Fil ...

  6. linux用户配置和用户权限

    一.查看用户: (1)在终端里.输入:cat /etc/passwd,查看/etc/passwd文件就行了.(2)看第三个参数:500以上的,就是后面建的用户了.其它则为系统的用户. 查看当前在线用户 ...

  7. Unity3D 批量图片资源导入设置

    原地址:http://blog.csdn.net/asd237241291/article/details/8433548 创文章如需转载请注明:转载自 脱莫柔Unity3D学习之旅 QQ群:[] 本 ...

  8. Winform设置相关

    >>  Winform查找根目录 1) AppDomain.CurrentDomain.BaseDirectory 地址为: d:\MyProject\Bin\  Application. ...

  9. javascript 注意事项

    1.submit input 标签的 type里的submit是提交表单的按钮 提交时应注意 为 标签加上 “name=""”字段和form标签,才能达到想要的效果  2.正则表达 ...

  10. HDU4512完美队形I && HDU1423 Greatest Common Increasing Subsequence (LCIS)

    填坑的时候又到啦,校赛因为不会LCIS所以吃了大亏,这里要补起来.LCIS就是在两个串里找最长上升子序列,相关的博客有很多,这里自己就不写那么多了. http://www.cnblogs.com/ja ...