C#中 As 和强制转换的总结
1.1.1 摘要
C#是一门强类型语言,一般情况下,我们最好避免将一个类型强制转换为其他类型,但有些时候难免要进行类型转换。
先想想究竟哪些操作可以进行类型转换(先不考虑.NET提供的Parse),一般我们都有以下选择:
- 使用as操作符转换,
- 使用传统C风格的强制转型
- 使用is来做一个转换测试,然后再使用as操作符或者强制转
1.1.2 正文
正确的选择应该是尽可能地使用as操作符,因为它比强制转型要安全,而且在运行时层面也有比较好的效率(注意的是as和is操作符都不执行任何用户自定义的转换,只有当运行时类型与目标转换类型匹配时,它们才会转换成功)。
现在我们通过一个简单的例子说明as和强制转换之间的区别,首先我们定义一间获取不同类型对象的工厂,然后我们把未知类型转换为自定义类型。
object o = Factory.GetObject();
MyType t = o as MyType;
if (t ==null)
{
//转换成功
}
else
{
//转换失敗
} object o = Factory.GetObject();
try
{
MyType t = (MyType) o;
if (t !=null)
{
////转换成功
}
else
{
////转换失敗
} }
catch
{
////异常处理
}
通过上述代码我们发现as类型转换失败时值为null不抛出异常,但强制转换如果转换失败会抛出异常所以我们要添加异常处理。
现在我们对as和强制转换有了初步的了解,假设现在我们定义了一个抽象类Foo,然后Foo1继承于它,并且再定义一个基类Logger,在Foo1中定义与Logger类型隐式转换具体如下:
Foo1 myFoo; //// Inherits abstract class.
Logger myFoo; //// base class. publicclass Foo1 : Foo
{
private Logger _value; ///<summary>
/// 隐式自定义类型转换。
///</summary>
///<param name="foo1"></param>
///<returns></returns>
publicstaticimplicitoperator Logger(Foo1 foo1)
{
return foo1._value;
}
}
现在我们猜猜看以下的类型转换是否成功(提示:从编译和运行时类型转换角度考虑)。
object myFoo = container.Resolve<Foo>(); //获取未Foo1类型 try
{
Logger myFoo1 = (Logger)myFoo;
if (myFoo1 !=null)
{
Console.WriteLine("Covert successful.");
}
}
catch
{
Console.WriteLine("Covert failed.");
}
相信聪明的大家已经想出答案了,激动人心的时刻到了现在让我们公布答案:转换失败抛出异常。
图1转换失败结果
首先我们要从编译和运行时角度来分析,在编译时myFoo的类型为System.Object,这时编译器会检测是否存在自定义由Object到Logger的类型转换。如果没有找到合适转换,编译器将生成代码检测myFoo的运行时类型和Logger比较,由于myFoo的运行时类型为Foo1,而且我们自定义了由Foo1到Logger的类型转换,估计这样可以转换成功了吧!然而恰恰没有转换成功,这究竟是什么原因呢?让我们了解一下编译器对于隐式类型转换的原理吧。
图2编译和运行时自定义类型转换
通过上图我们发现用户自定义的转换操作符只作用于对象的编译时类型,而非运行时类型上,OK现在让修改一下代码让我们编译器认识自定义类型中。
using (IUnityContainer container =new UnityContainer())
{
UnityConfigurationSection section = (UnityConfigurationSection)
ConfigurationManager.GetSection("unity"); //获取container名称为CfgClass下的配置
section.Containers["CfgClass"].Configure(container);
object tempFoo = container.Resolve<Foo>(); //获取未Foo1类型
Foo1 myFoo = tempFoo as Foo1; //使用as先把object转型为Foo1
try
{
Logger myFoo1 = (Logger)myFoo;
if (myFoo1 !=null)
{
Console.WriteLine("Covert successful.");
}
}
catch
{
Console.WriteLine("Covert failed.");
} Console.ReadKey();
}
图3转换成功结果
现在类型可以转换成功,这是因为编译器使用了我们自定义的隐式转换,由于myFoo这次的编译类型为Foo1,编译器首先查找是否存在Foo1和Logger自定义转换类型,由于我们定义了一种由Foo1到Logger的隐式类型转换所以转换成功。
通过上述我们发现了as给我们带来的好处,但是有一点我们要注意的是as只能用于引用类型不能用于值类型。那我就有个问题了在进行类型转换之前如果我们并不知道要转换的是值类型还是引用类型,那该怎么办呢?现在是is登场的时候了。
bject tempFoo = container.Resolve<Foo>(); //获取未Foo1类型
int myInt = tempFoo asint; //compile error
as不能用于值类型,这是因为值类型不能为null(注意:C#2.0中,微软提供了Nullable类型,允许用它定义包含null值,即空值的数据类型)像这种情况我们应该使用强制类型转换。
object tempFoo = container.Resolve<Foo>(); //获取未Foo1类型
try
{
int myInt = (int)tempFoo; //转换成功
if (myFoo1 !=null)
{
Console.WriteLine("Covert successful.");
}
}
catch
{
Console.WriteLine("Covert failed.");
}
大家可以发现和我们之前使用的强制转换类似,而且还有处理异常,现在修改一下我们代码让它更加简洁实现如下:
object tempFoo = container.Resolve<Foo>(); //获取未Foo1类型
int i =0; //值类型转换
if (tempFoo isint)
{
i = (int) tempFoo;
} object tempFoo = container.Resolve<Foo>(); //获取未Foo1类型
Logger myFoo1 =null; //引用类型转换
if (tempFoo is Logger)
{
myFoo1 = tempFoo as Logger;
}
1.1.3 总结
as和强制转换之间最大的区别就在于如何处理用户自定义的转换。操作符 as和 is 都只检查被转换对象的运行时类型,并不执行其他的操作。如果被转换对象的运行时类型既不是所转换的目标类型,也不是其派生类型,那么转型将告失败。但是强制转型则会使用转换操作符来执行转型操作,这包括任何内建的数值转换(如:long转int)。
一般情况我们应该先考虑使用as进行类型转换,然后再考虑使用is,最后才考虑使用强制转换。
as |
强制转换 |
|
转换失败是否抛出异常 |
No |
Yes |
支持值类型和引用类型转换 |
只支持引用类型 |
Yes |
C#中 As 和强制转换的总结的更多相关文章
- OC中的类型强制转换
在Objective-C中,以数字格式组成的字符串经常需要转换为NSNumber对象后再使用.例如有一个字符串对象@"111.22",需要转为NSNumber对象,最简单的方法就是 ...
- java 中数据的强制转换 和计算的补码运算
原码 反码 补码的定义与运算 1原码: 原码是将十进制或者其他进制的数转换为二进制表示(且要根据数据的类型转换) 如:130 (默认是Int类型,则是4个字节) 原码是:00000000 000000 ...
- php中数据类型的强制转换
1.在PHP开发种在很多的地方要涉及到数据类型的转换,尤其是涉及到金额的数据类型,一定要转换成float类型,否则在入库的时候可能会因为数据类型的不同覆盖掉之前的金额.(字符串和float类型相加) ...
- How to: Use XPO Upcasting in XAF 如何:在 XAF 中使用 XPO 强制转换
In this topic, you will learn how to use the Upcasting feature of XPO in XAF. It is useful when you ...
- PHP 变量类型的强制转换 & 创建空对象
PHP 在变量定义中不需要(或不支持)明示的类型定义:变量类型是根据使用该变量的上下文所决定的. 也就是说,如果把一个字符串值赋给变量 var,var 就成了一个字符串.如果又把一个整型值赋给 var ...
- PHP强制转换类型
PHP强制转换类型 获取数据类型 : 1.如果想查看某个表达式的值和类型,用var_dump(). 2.如果只是想得到一个易读懂的类型的表达方式用于调试,用 gettype().3.要查看某个类型 ...
- C++指针类型间强制转换
深入理解指针类型间的转换 C++中指针的强制转换 强制类型转换(int).(int&)和(int*)的区别 内存中的地址 地址的本质就是一串0和1的机器代码,内存中的地址没有明确数据类型,但地 ...
- Php中的强制转换详解
强制转换中分为两种,第一种就只临时转换,和永久转换.在临时转换中呢,首先可以通过第一中方式来显示,就是小括号的形式,临时转换成整型我们可以通过(int)都是这样的形式,或者是(integer)临时转换 ...
- c++中的强制转换static_cast、dynamic_cast、reinterpret_cast的不同用法儿
c++中的强制转换static_cast.dynamic_cast.reinterpret_cast的不同用法儿 虽然const_cast是用来去除变量的const限定,但是static_cast ...
随机推荐
- Sql分隔字符串方法--split
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO --DEClARE @str varchar(500)='a,b2,v5,d3,ew,2,3,dd' ...
- Unable to execute dex: Multiple dex files define
这是一个编译错误,在ADT的编译器和SDK的工具有差异或是版本不一致时常会出现的一个问题,解决的方案如下: 第一步: updated eclipse (Help->Check for updat ...
- ThreadLocal的设计与使用(原理篇)
在jdk1.2推出时开始支持java.lang.ThreadLocal.在J2SE5.0中的声明为: public class ThreadLocal<T> exte ...
- 《ASP.NET1200例》解决母版页报错“内容控件必须是内容页中的顶级控件,或是引用母版页的嵌套母版页。”
VS2005下,添加了母版页这个控件,我们可以讲N个页面中共同的部分放在母版页来实现,并让WEB窗体集成自我们的母版页,就可以让我们的站点具有统一的风格了.在VS2005SP1之前的版本中,我们只能创 ...
- Sharepoint程序员应该了解的知识
做为一个Sharepoint程序员应该了解的知识:注意,我说的是程序员.因为我一直把自己看一个普普通通的程序员. 前提: 要知道网络基础(包括DHCP.IP.掩码.DNS.网关.广播),会装操作系统( ...
- discuz 帖子模块用到的表及自动发帖函数
最近在做一个discuz的插件,由于需要程序自动生成并调用discuz已经存在插件的帖子.然而这就相当于自动发帖的功能了.网上找了一下,大部分都是通过curl模拟登陆,模拟发帖的,这显然不满足我的要求 ...
- 如何在Ubuntu下安装”.deb“、”.bin“、”.tar.gz“、”.tar.bz2“格式的软件包!
今天在Ubuntu11.10中安装Google chrome浏览器是遇到了问题,下载好的“.deb”格式的安装文件google-chrome-stable.deb双击后或者右键快捷菜单选择 Synap ...
- UVA 11827 Maximum GCD (输入流)
题目:传送门 题意:求n个数的最大公约数,暴力不会超时,难点在没有个数控制的输入. 题解:用特殊方法输入. #include <iostream> #include <cmath&g ...
- Hadoop 1.1.2 eclipse plugin 编译 win7 集成
Windows平台上使用ANT编译Hadoop Eclipse Plugin 一.准备工作: 1.安装JDK 下载页面:http://www.oracle.com/technetwork/java ...
- SVN常见错误和版本冲突解决
之前在Eclipse下面误删除了svn的一些插件包,后来重装了就问题重重,在这里还是建议, Windows下SVN最好使用桌面版,在文件管理器下面更新和提交. 1.常见错误整理 #, c-format ...