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 ...
随机推荐
- springmvc 项目完整示例06 日志–log4j 参数详细解析 log4j如何配置
Log4j由三个重要的组件构成: 日志信息的优先级 日志信息的输出目的地 日志信息的输出格式 日志信息的优先级从高到低有ERROR.WARN. INFO.DEBUG,分别用来指定这条日志信息的重要程度 ...
- jsp&servlet学习笔记
1.路径引用问题 一个css.jsp.html.或者javascript文件从从一个工程复制到另一工程,如果引用的时候使用的时相对路径,看似没有错误,但是却一直引用不进来,这时候要使用绝对路径,这样才 ...
- HDU 1875 畅通工程再续 (prim最小生成树)
B - 畅通工程再续 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit S ...
- bellman ford优先队列优化简介模板
#include<iostream>#include<cstdio>#include<utility>#include<queue>#include&l ...
- HDOJ 2095
find your present (2) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/1024 K (Java/Oth ...
- 在 FREEBUF 投放广告
在 FREEBUF 投放广告 FreebuF黑客与极客—高质量的全球互联网安全媒体,同时也是爱好者们交流.分享安全技术的最佳平台.本站读者群以IT.政企信息安全人员.互联网安全爱好者和学生为主,对互联 ...
- MVC NonAction属性
3.1. NonAction属性 若将NonAction属性应用在Controller中的Action方法上,即使该Action方法是公共方法,也会告知ActionInvoker不要选取这个Actio ...
- OpenStack
[官网]http://www.openstack.org/ [视频教程1]http://blog.csdn.net/u010973404/article/details/16841229 [视频教程2 ...
- svn 设置
\Release *\Debug *\bin *\Bin *\obj *\_ReSharper* *\.hg *.ReSharper *.resharper *\Generated_Code *\VB ...
- Java异常与异常处理简单使用
异常就是程序运行过程中阻止当前方法或作用域继续执行的问题: 任何程序都不能保证完全正常运行,当发生异常时,需要我们去处理异常,特别是一些比较重要的场景,异常处理的逻辑也会比较复杂,比如:给用户提示.保 ...