[C#] as 和 is 运算符以及安全的类型强制转换

根据MSDN的说明:由于对象是多态的,因此基类类型的变量可以保存派生类型。若要访问派生类型的方法,需要将值强制转换回该派生类型。不过,在这些情况下,如果只尝试进行简单的强制转换,会导致引发 InvalidCastException 的风险。鉴于这个过程是不安全的,因此需要用 try - catch 语句块来进行保护,例如比较安全的代码方式应该如下所示:


// 有一object类型的待转换对象 objTest
GivenType value = null;
try
{
value = (GivenType) objTest;
}
catch( Exception e )
{
MessageBox.Show( e.Message );
}

但是如上的写法在C#中已经属于过时的写法,而且也属于比较低效的写法。但是类似的转换会经常发生,为了避免异常导致的低效和代码的不简洁,C# 提供 is 和 as 运算符来进行转换。可以使用这两个运算符来测试强制转换是否会成功,而没有引发异常的风险。

一、is 运算符

is 运算符检查对象是否与给定类型兼容。例如,if ( obj is MyObject ) 将检查对象 obj 是否为 MyObject 类型的一个实例,或者是从 MyObject 派生的一个类型的实例。

对于is表达式的结果应该这么看待:如果所提供的对象(表达式)非空,并且可以被强制转换为所提供的类型而不会引发异常,则is表达式的结果就为true,否则为false。

通常使用is表达式的情况是程序运行时才计算类型兼容性,如果已知表达式的值始终为true或者fale,将会导致编译时的警告。

注意:is运算符只考虑引用转换、装箱转换和拆箱转换,不考虑其他转换(包括用户定义的转换)。例如虽然intdouble是类型兼容的,但是使用is运算符的结果却是false。

其他需要注意的:

  • 不能重载is运算符;
  • 在is运算符左侧不允许使用匿名方法(Lambda表达式例外)。

二、as 运算符

as 运算符用于在兼容的引用类型之间执行类似于强制类型转换的操作。与强制类型转换不同的是,如果无法进行转换,as运算符将返回null而不是引发异常。

语法:

expression as type

等效于:

expression is type ? (type) expression : (type) null

注意:as 运算符只能执行引用转换和装箱转换,不能执行拆箱转换(应使用is运算符判断配合强制类型装换来完成),也不能执行其他转换,如用户定义的转换(这类转换应该首先需要相应类型提供转换函数并使用强制转换表达式来完成,或者使用case语句等其他方法来执行)。下面举例说明:

2.1 不能使用 as 运算符进行拆箱转换

即 as 运算符不能应用在值类型数据,如下写会出现编译错误:

object objTest = 11;
int intValue = objTest as int;

正确的写法是:使用is操作符,再加上显式的类型转换操作,就可以安全完成转换,例如:

object objTest = 11;
if ( objTest is int )
{
int intValue = (int) objTest;
}

2.2 不能使用 as 运算符完成用户定义的转换

要想使用户定义的转换操作能正确完成,需要在原类型中增加类型转换操作符函数,例如:

public class NewTypeOne

{

public static explicit operator NewTypeTwo( NewTypeOne objTypeOne )

{

//Convert object into new type

}

}

并使用如下强制类型转换(不能使用 as 运算符):

NewTypeOne objTypeOne = new NewTypeOne();

NewTypeTwo newTestTwo = (NewTypeTwo)newTestOne;

2.3 对 as 运算符使用可空类型

允许使用 as 运算符完成基本数据类型(已知值类型)之间的转换,但是由于使用 as 运算符可能产生null值,应注意可能需要对 as 运算符使用 nullable 类型,否则同样可能抛出异常。

下面是摘自MSDN的代码:

void UseAsWithNullable(System.ValueType val)
{
int? j = val as int?;
if (j != null)
{
Console.WriteLine(j);
}
else
{
Console.WriteLine("Could not convert " + val.ToString());
}
}

三、as 运算符和 is 运算符的效率比较

通常,as 运算符更高效一些,因为如果可以成功进行强制转换,它会实际返回强制转换值。而 is 运算符只返回一个布尔值,可能在表达式为true时,还需要进行显示的转换,就需要执行两次类型兼容检查,例如:

object o ="abc";

if ( o is string) //执行第一次类型兼容性检查

{

string s = (string)o; //执行第二次类型兼容性检查,并转换

MessageBox.Show( "转换成功!" ); 

}

else

{

MessageBox.Show( "转换失败!" );

}

而使用as运算符,可以改写为:

object o ="abc";

string s = oasstring;//执行第一次类型兼容性检查,并返回结果

if(s != null)

MessageBox.Show("转换成功!");
else
MessageBox.Show("转换失败!");

对比两种方式,is 需要做两次对象的类型检查;而 as 需要做一次对象类型检查,再加一次null的检查,但是null检查的开销比对象类型检查少,因此相对来说,as的方法效率高些。当然,只是检测类型是否相符那么只用is就可以了,如果要进行类型转化可以直接用as。

四、类型转换总结

综上所述,那么在进行类型转换的时候,可以按照如下的方式进行选择。

类型转换

使用操作

Object --> 已知引用类型

使用 as 操作符来完成

Object --> 基本数据类型(拆箱)

先使用 is 操作符来进行判断,再用强制转换方式进行转换

用户定义类型之间转换

首先需要相应类型提供转换函数,再用强制转换方式进行转换

基本数据类型之间转换

最好使用.Net提供的Convert类所涉及的静态方法

其他类型转换相关:

1. 任何类型都可以转换为其基类类型,用隐式转换即可完成;

2. 任何类型转换为其派生类型时,必须进行显示转换。如:(类型名)对象名;

3. 使用 GetType 可以取得任何对象的精确类型;

4. 基本数据类型是都是已知的值类型,可以使用 Convert 类实现类型转换;

5. 除了 string 以外的其他类型都有 Parse 方法,用于将字符串类型转换成对应的基本类型;

6. 值类型和引用类型的转换称为装箱(boxing)或拆箱(unboxing)。(根据MSDN编程指南:装箱是将值类型转换为object类型或由此值类型实现的任一接口类型的过程。当CLR对值类型进行装箱时,会将该值包装到System.Object内部,再将后者存储在托管堆上。取消装箱将从对象中提取值类型。)

参考:

1. 如何:使用 as 和 is 运算符安全地进行强制转换(C# 编程指南). MSDN. http://msdn.microsoft.com/zh-cn/library/cc488006

2. as(C#参考). MSDN. http://msdn.microsoft.com/zh-cn/library/cscsdfbt

3. is(C#参考). MSDN. http://msdn.microsoft.com/zh-cn/library/scekt9xw

4. C# 中 as 和 is 的用法. http://www.cppblog.com/luyulaile/archive/2011/03/14/141773.html

5. C# as 与 is. http://blog.csdn.net/pengfeixiong/article/details/7409875

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值