1.1.1 摘要

C#是一门强类型语言,一般情况下,我们最好避免将一个类型强制转换为其他类型,但有些时候难免要进行类型转换。

先想想究竟哪些操作可以进行类型转换(先不考虑.NET提供的Parse),一般我们都有以下选择:

  • 使用as操作符转换,
  • 使用传统C风格的强制转型
  • 使用is来做一个转换测试,然后再使用as操作符或者强制转

1.1.2 正文

正确的选择应该是尽可能地使用as操作符,因为它比强制转型要安全,而且在运行时层面也有比较好的效率(注意的是as和is操作符都不执行任何用户自定义的转换,只有当运行时类型与目标转换类型匹配时,它们才会转换成功)。

现在我们通过一个简单的例子说明as和强制转换之间的区别,首先我们定义一间获取不同类型对象的工厂,然后我们把未知类型转换为自定义类型。

objecto =Factory.GetObject();
MyType t =o asMyType;
if(t ==null)
{
//转换成功
}
else
{
//转换失敗
}

objecto =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.

publicclassFoo1 : Foo
{
privateLogger _value;

///<summary>
///隐式自定义类型转换。
///</summary>
///<param name="foo1"></param>
///<returns></returns>
publicstaticimplicitoperatorLogger(Foo1 foo1)
{
returnfoo1._value;
}
}

现在我们猜猜看以下的类型转换是否成功(提示:从编译和运行时类型转换角度考虑)。

objectmyFoo =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 =newUnityContainer())
{
UnityConfigurationSection section =(UnityConfigurationSection)
ConfigurationManager.GetSection("unity"); //获取container名称为CfgClass下的配置
section.Containers["CfgClass"].Configure(container);
objecttempFoo =container.Resolve<Foo>(); //获取未Foo1类型
Foo1 myFoo =tempFoo asFoo1; //使用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登场的时候了。

bjecttempFoo =container.Resolve<Foo>(); //获取未Foo1类型
intmyInt =tempFoo asint; //compile error

as不能用于值类型,这是因为值类型不能为null(注意:C#2.0中,微软提供了Nullable类型,允许用它定义包含null值,即空值的数据类型)像这种情况我们应该使用强制类型转换。

objecttempFoo =container.Resolve<Foo>(); //获取未Foo1类型
try
{
intmyInt =(int)tempFoo; //转换成功
if(myFoo1 !=null)
{
Console.WriteLine("Covert successful.");
}
}
catch
{
Console.WriteLine("Covert failed.");
}

大家可以发现和我们之前使用的强制转换类似,而且还有处理异常,现在修改一下我们代码让它更加简洁实现如下:

objecttempFoo =container.Resolve<Foo>(); //获取未Foo1类型
inti =0; //值类型转换
if(tempFoo isint)
{
i =(int) tempFoo;
}

objecttempFoo =container.Resolve<Foo>(); //获取未Foo1类型
Logger myFoo1 =null; //引用类型转换
if(tempFoo isLogger)
{
myFoo1 =tempFoo asLogger;
}

1.1.3 总结

as和强制转换之间最大的区别就在于如何处理用户自定义的转换。操作符 as和 is 都只检查被转换对象的运行时类型,并不执行其他的操作。如果被转换对象的运行时类型既不是所转换的目标类型,也不是其派生类型,那么转型将告失败。但是强制转型则会使用转换操作符来执行转型操作,这包括任何内建的数值转换(如:long转int)。

一般情况我们应该先考虑使用as进行类型转换,然后再考虑使用is,最后才考虑使用强制转换。

as

强制转换

转换失败是否抛出异常

No

Yes

支持值类型和引用类型转换

只支持引用类型

Yes

转载于:https://www.cnblogs.com/xpvincent/p/3213922.html

C#中 As 和强制转换的总结相关推荐

  1. C 语言中结构体强制转换--实验

    2019独角兽企业重金招聘Python工程师标准>>> 对于C语言中结构体强制转换做了如下实验, 或许可以解惑一些问题 对于结构体, 我理解的属性有: 成员的顺序, 成员的类型,成员 ...

  2. C++中指针的强制转换

    转自:https://blog.csdn.net/u012273127/article/details/53260978 其又转自:http://blog.csdn.net/mhjcumt/artic ...

  3. 引用类型的转换 java,java中引用类型的强制转换

    public class TestPerson { public static void main(String[] args) { // 向上类型转换,正常运行 Animal a = new Cat ...

  4. java中为什么不能强制转换_为什么Java中的强制转换异常致命?

    根据this文章: In contrast to static type checking, dynamic type checking may cause a program to fail at ...

  5. java中如何进行强制转换?

    转型有两种: 向上转型和向下转型(强制转型) 两种分别如下: 一种是向上转型 对于基础数据类型 , 可以自动转型 ,比如: int a = 10; long b = a; 这里就是把int型转成了lo ...

  6. C++中1LL避免强制转换

    变量a为int型,b为long long型 赋值时 b = a * 1LL a * 1LL 之后类型就转换为long long,

  7. malloc的强制转换

    因为数据结构课在使用malloc函数的时候一直很迷惑,为什么一定需要在前面加上一个强制转换语句,像是这样:int *a = (int *)malloc(sizeof(int)*3);. 为此我在菜鸟教 ...

  8. C++指针类型间强制转换

    深入理解指针类型间的转换 C++中指针的强制转换 强制类型转换(int).(int&)和(int*)的区别 内存中的地址 地址的本质就是一串0和1的机器代码,内存中的地址没有明确数据类型,但地 ...

  9. php中int()强制转换,php下intval()和int强制转换使用的区别是什么

    php下intval()和int强制转换使用的区别是:1.[intval()]如果参数是字符串,则返回字符串中第一个不是数字的字符之前的数字串所代表的整数值:2.转换为int的PHP字符串,在使用之前 ...

  10. C++中的四类强制转换?

    C++中的四类强制转换? 例: class ClassA { public: virtual ~ ClassA() {          }      virtual void FunctionA() ...

最新文章

  1. 2021年AI网络安全发展趋势
  2. 深度复制_Python 列表切片陷阱:引用、复制与深复制
  3. Asp.Net_文件操作基类
  4. css3高级和低级样式属性先后顺序
  5. python模块导入_Python模块及其导入
  6. 设计模式之代理模式,学习笔记
  7. Github 再现失误:部分用户密码明文暴漏
  8. jQuery文档处理程序
  9. ORB-SLAM3从理论到代码实现(三):Optimizer全局优化
  10. 通过hive将excel文件_hive 之 将excel数据导入hive中 : excel 转 txt
  11. 计算机技术中采用二进制,计算机中采用二进制编码的原因是什么
  12. 笔记本电脑无法连接WiFi,如何解决
  13. java编写平行四边形的代码_Java代码编写四边形
  14. css实现视频文字特效
  15. linux打包文件夹命令
  16. 通俗易懂理解——双向LSTM
  17. 计算机英文专业文献翻译,计算机科学与技术专业外文翻译外文文献英文文献记录...
  18. 逼死程序员的翟某被媒体起底,疑有 5 个对象离了 4 次获利上亿
  19. 【千锋】网络安全学习笔记(三)
  20. linux yum pcre安装路径,yum 安装的pcre源码目录在哪

热门文章

  1. 百度之星初赛A 今夕何夕
  2. Codeforces Round #409 C. Voltage Keepsake(二分+思维)
  3. [转]网友monkeylarry研究生期间我们应该做什么
  4. [转]一阶自回归模型和二阶自回归模型
  5. codeforces C. Ryouko's Memory Note
  6. WEB前端开发书籍推荐
  7. Busybox是什么?
  8. 数字金额转为大写金额(C#)
  9. Android 中的长度单位详解 dp、sp、px、in、pt、mm 转载
  10. [导入]哪种图像格式最好?