[你必须知道的.NET] 第一回:恩怨情仇:is和as

发布日期:2007.4.7 作者:Anytao

©2007 Anytao.com 转贴请注明出处,留此信息。

 

本文将介绍以下内容:

• 类型转换

• is/as操作符小议 

1. 引言 

类型安全是.NET设计之初重点考虑的内容之一,对于程序设计者来说,完全把握系统数据的类型安全,经常是力不从心的问题。现在,这一切已经在微软大牛们的设计框架中为你解决了。在.NET中,一切类型都必须集成自System.Object类型,因此我们可以很容易的获得对象的准确类型,方法是:GetType()方法。那么.NET中的类型转换,应该考虑的地方有那些呢?

2. 概念引入

类型转换包括显示转换和隐式转换,在.NET中类型转换的基本规则如下:

  • 任何类型都可以安全的转换为其基类类型,可以由隐式转换来完成;
  • 任何类型转换为其派生类型时,必须进行显示转换,转换的规则是:(类型名)对象名;
  • 使用GetType可以取得任何对象的精确类型;
  • 基本类型可以使用Covert类实现类型转换;
  • 除了string以外的其他类型都有Parse方法,用于将字符串类型转换为对应的基本类型;
  • 值类型和引用类型的转换机制称为装箱(boxing)和拆箱(unboxing)。

3. 原理与示例说明

浅谈了类型转换的几个普遍关注的方面,该将主要精力放在is、as操作符的恩怨情仇上了。类型转换将是个较大的话题,留于适当的时机讨论。

is/as操作符,是C#中用于类型转换的,提供了对类型兼容性的判断,从而使得类型转换控制在安全的范畴,提供了灵活的类型转换控制。

is的规则如下:

  • 检查对象类型的兼容性,并返回结果,true或者false;
  • 不会抛出异常;
  • 如果对象为null,则返回值永远为false。

其典型用法为:

 1object o = new object();
 2
 3class A
 4
 5{
 6
 7}

 8
 9if (o is A)  //执行第一次类型兼容检查
10
11{
12
13  A a = (A) o;  //执行第二次类型兼容检查
14
15}

16
17

 as的规则如下:

  • 检查对象类型的兼容性,并返回结果,如果不兼容就返回null;
  • 不会抛出异常;
  • 如果结果判断为空,则强制执行类型转换将抛出NullReferenceException异常。

其典型用法为: 

 1object o = new object();
 2
 3class B
 4
 5{
 6
 7}

 8
 9B b = o as B;  //执行一次类型兼容检查
10
11if (b != null)
12
13{  
14
15  MessageBox.Show("b is B's instance.");
16
17}

18
19

4. 结论

纵上比较,is/as操作符,提供了更加灵活的类型转型方式,但是as操作符在执行效率上更胜一筹,我们在实际的编程中应该体会其异同,酌情量才。 

参考文献

(USA)Jeffrey Richter, Applied Microsoft .NET Framework Programming

 (USA) Stanley B. Lippman, C# Primer

 

©2007 Anytao.com 转贴请注明出处,留此信息。

本贴子以现状提供且没有任何担保,同时也没有授予任何权利。
This posting is provided "AS IS" with no warranties, and confers no rights.

posted @ 2007-04-07 16:57 Anytao 阅读(17462) 评论(94)  编辑 收藏 网摘 所属分类: 01 [你必须知道的.NET]

  回复  引用  查看    
#1楼2007-04-07 17:09 | 随风流月      
"除了string以外的其他类型都有Parse方法,用于将基本类型转换为字符串类型"
这一句好像反了,应该是将字符串类型转换为基本类型。感谢您的分享!

  回复  引用  查看    
#2楼[楼主]2007-04-07 17:17 | Anytao      
@随风流月
呵呵,及是,马上修改。

  回复  引用  查看    
#3楼2007-04-07 19:23 | Artech      
@随风流月
除了string以外的其他类型都有Parse方法?应该是“其他的Primitive Type”吧

  回复  引用  查看    
#4楼2007-04-07 19:37 | Artech      
“as操作符在执行效率上更胜一筹”,我觉得比较准确的说法是利用as模式比is模式具有更好的性能,毕竟is和as两个操作符本身不具有可比性。因为采用as模式只进行一个类型的验证,而is模式则会进行两次。
  回复  引用  查看    
#6楼2007-04-07 23:02 | 布尔      
常用于访问通用对象缓存情况下,如
Person p = new Person()

session["keyName"] = p;
Person p = session["keyName"] as Person;

cache.Add("keyName", p)
Person p = cache.Get("keyName") as Person;

  回复  引用  查看    
#7楼[楼主]2007-04-07 23:52 | Anytao      
@Artech
对,这么表达应该更合适。

  回复  引用  查看    
#8楼[楼主]2007-04-07 23:56 | Anytao      
@壮志
谢谢,值得进一步研究

  回复  引用  查看    
#9楼[楼主]2007-04-08 00:00 | Anytao      
@布尔
对,其实,对象转型的情况下,都可以考虑以as模式类判断,否则应该进行异常处理。

  回复  引用  查看    
#10楼2007-04-08 12:27 | Artech      
@Anytao
异常处理是最不应该推荐的方法,这种方法的性能将会非常地差。

  回复  引用  查看    
#11楼[楼主]2007-04-08 13:25 | Anytao      
@Artech
异常处理是有性能损失,但是对可以预见的异常发生,我的理解是以性能换稳定,as模式中我们就可以捕捉NullReferenceException异常来处理,我觉得更加妥当。

  回复  引用    
#12楼2007-04-08 14:09 | zhuispeed[未注册用户]
effective c# 里面也有一个item是讲这个问题的,按照里面的意思是 尽量使用as ,:)
  回复  引用    
#13楼2007-04-08 16:34 | duanxingchuan[未注册用户]
你好,我想请教一个问题。
在.net环境写的程序,怎样在没有装.net的机子上运行?就是客户机不装.net环境。更简单的说,就是如何把.net程序转换成win32程序。
非常感谢!!!!
若方便的话,可以给我发email:17look@163.com 或 qq: 624611400 .
谢谢大家了!!!!!!!!!

  回复  引用  查看    
#14楼[楼主]2007-04-08 20:38 | Anytao      
@zhuispeed
谢谢提醒,以后有时间看看

  回复  引用  查看    
#15楼2007-04-09 13:33 | Artech      
@Anytao
当然Exception Handler就像是给Application上了个保险。我的意思是尽量预测出现类不能兼容的情况,尽可能不要让Exception Handler起作用。
有这样一个原则:不到万不得已,不要把抛出Exception作为一种运行的条件来设计你的程序。

  回复  引用  查看    
#16楼2007-04-09 13:37 | Artech      
@duanxingchuan
我们一般通过.NET编写的托管的程序,托管程序的执行必须有个托管的执行环境,也就是必须加载CLR,所以托管程序在没有.NET,也就是没有安装.NET Framework(CLR + FCL)的环境中是不能执行的。

  回复  引用  查看    
#17楼2007-04-09 16:49 | 阿齐      
@duanxingchuan
看看http://www.remotesoft.com/">http://www.remotesoft.com/,其中的Salamander工具--据其介绍,可以生成本地代码(但是我没试过,嘿嘿)

  回复  引用  查看    
#18楼[楼主]2007-04-10 13:07 | Anytao      
@Artech
所言甚是,异常处理最重要的是预见可能出现的异常,这样对性能对安全都是应该的。

  回复  引用    
#19楼2007-04-11 16:27 | wqxh[未注册用户]
大概意思讲了,但是不够详细。
可以参考Effective C#,我觉得那里讲得最详细。

  回复  引用  查看    
#20楼2007-04-26 22:31 | 宋欢.net      
Effective C#这本书怎么样呢?
  回复  引用  查看    
#21楼2007-04-26 23:22 | 阿齐      
回:Effective C#这本书怎么样呢?
答:这本书很烂

  回复  引用  查看    
#22楼[楼主]2007-05-25 00:08 | Anytao      
@wqxh
希望受用

  回复  引用  查看    
#23楼[楼主]2007-05-25 00:10 | Anytao      
@Sean(陈阳)
@宋欢.net
@阿齐
这本书我没有研读过,大家都提到,可以找时间看看, Effective C++倒是看过,确实是经典。至于Effective C#,还是有时间再来讨教。

  回复  引用  查看    
#24楼2007-05-25 15:54 | 周奔驰      
标题党,看不出is和as 有何深仇大恨
  回复  引用  查看    
#25楼[楼主]2007-05-25 16:52 | Anytao      
@周奔驰
不是标题党,是内容党,以内容和观点说话,标题只是个摆设.

  回复  引用  查看    
#26楼2007-06-22 14:00 | steven-chen      
不错,学习了!
  回复  引用    
#27楼2007-07-11 09:26 | pinty[未注册用户]
学习~_~
  回复  引用  查看    
#28楼[楼主]2007-07-11 13:10 | Anytao      
@steven-chen
谢谢关注.

  回复  引用  查看    
#29楼[楼主]2007-07-11 13:10 | Anytao      
@pinty
一起进步.

  回复  引用  查看    
#30楼[楼主]2007-07-11 13:11 | Anytao      
@念时
谢谢关注,继续努力。

  回复  引用    
#31楼2007-07-17 10:15 | doll-net
is 和 as 的用处在某种程度上讲是不挨边的
is 是判断可否将一种类型当作另一种类型使
as 是将一种类型转为另一种类型,转换失败则返回null
就是从你的文章里我也看不出is 和 as有啥恩怨情仇~~~~

  回复  引用  查看    
#32楼2007-07-18 18:11 | 脚印      
as 为类型转换,但是他要求转换以后的类型为引用类型(不晓得是否正确)

int a = 1;
object b=a;
int c = b as int //这里就会提示错误2 as 运算符必须与引用类型一起使用(“int”是值类型)


如果这样的话是不是说 as 只能用与

class A
{
.....
}
A a = new a();
object b=a;
A c= b as A;


  回复  引用  查看    
#33楼[楼主]2007-08-14 08:55 | Anytao      
@doll-net
某种程度上,is和as是可以拿出来比较,作为类型转换中的一种常用的手段,注意什么,推荐什么,这是本文的主题。
在此强调的是类型安全。

  回复  引用  查看    
#34楼2007-09-13 15:17 | 念时      
用as来转换类型是方便了也保证了安全性,而且不用Try catch……
is 和 as 应该说各有各的用处,只看具体情况了

  回复  引用  查看    
#35楼[楼主]2007-09-13 22:22 | Anytao      
@念时
某种意义上,是这样,这也是.NET本身的优点。

  回复  引用  查看    
#36楼2007-09-15 14:51 | 镜涛      
更赞同 is用来判断,as用于转换!
  回复  引用  查看    
#37楼2007-09-15 18:31 | Jacky_xu      
--引用--------------------------------------------------
镜涛: 更赞同 is用来判断,as用于转换!
--------------------------------------------------------
同意

  回复  引用  查看    
#38楼[楼主]2007-09-16 00:04 | Anytao      
@镜涛
@Jacky_xu
不错的补充:-)

  回复  引用  查看    
#39楼[楼主]2007-09-26 10:49 | Anytao      
@chinaifne
:-)

  回复  引用  查看    
#40楼2007-10-01 03:17 | ascliy      
学习,谢谢分享
  回复  引用  查看    
#41楼[楼主]2007-10-02 10:33 | Anytao      
@ascliy
对大家有用就行,实感欣慰。

  回复  引用    
#42楼2007-12-06 21:23 | 嘟嘟嘟嘟[未注册用户]
有个疑问
A a = new a();
object b=a;
A c= b as A;

这样的转化跟

A a = new a();
object b=a;
A c= (A)b;

对比,具体有什么区别呢?

  回复  引用  查看    
#43楼[楼主]2007-12-06 21:51 | Anytao      
@嘟嘟嘟嘟

as实现了引用类型的强制转换,不会引发异常,b as A可以等效于:
b is A ? (A)b : null

而显示类型转换不具有该特性,总结其主要区别:

1 as只能操作引用类型;(type)变量名可以应用于值类型和引用类型;
2 as不会引发不兼容类型转换异常,有性能优势;显示类型转换,可能引发异常,不推荐。

  回复  引用    
#44楼2007-12-07 18:30 | 嘟嘟嘟嘟 [未注册用户]
原来如此啊,以后要楼主多指教了
  回复  引用  查看    
#45楼[楼主]2007-12-07 19:32 | Anytao      
@嘟嘟嘟嘟
:-), 不敢不敢,我很喜欢讨论,谢谢参与。

  回复  引用    
#46楼2007-12-20 17:43 | zhslsnow[未注册用户]
呵呵,文章很好
只是导航没做好吧?找了很久没发现有到下一回的链接呃~

  回复  引用  查看    
#47楼[楼主]2007-12-20 17:59 | Anytao      
  回复  引用  查看    
#48楼2008-01-04 10:13 | 第4只苹果      
所以本文的推荐是:

A a = new A();
object b = a; //这是隐式,与is 和as 无关

A c= b as A; //这是LZ推荐的引用类型转换机制,对吗?

如果不成功c为null(当然这里是成功的了:))
if(c==null)
{
您打算 throw exception在这里吗?
}

  回复  引用  查看    
#49楼[楼主]2008-01-04 21:41 | Anytao      
@第4只苹果
所言正确,对于c==null是否抛出异常,视具体的情况而定,而抛出异常是通常的选择。

  回复  引用    
#50楼2008-05-21 18:48 | 玄武湖到西湖[未注册用户]


--引用----------------------------------------------
Anytao: @嘟嘟嘟嘟

as实现了引用类型的强制转换,不会引发异常,b as A可以等效于:
b is A ? (A)b : null

而显示类型转换不具有该特性,总结其主要区别:

1 as只能操作引用类型;(type)变量名可以应用于值类型和引用类型;
2 as不会引发不兼容类型转换异常,有性能优势;显示类型转换,可能引发异常,不推荐。
--------------------------------------------------------

b as A可以等效于:
b is A ? (A)b : null 这样的话使用 as 不是一样需要两次兼容检查吗?性能为何会好呢?

  回复  引用  查看    
#51楼[楼主]2008-05-23 15:40 | Anytao      
@玄武湖到西湖
我提到的
------------------------------
b as A可以等效于:
b is A ? (A)b : null
-----------------------------
是对as语义的解释,而非实际的执行过程,实现上你可以从IL的分析或者二者的差别:
object a = new object();
A b = a as A;

if (a is A)
{
A c = (A)a;
}
可以根据其IL进行进一步的分析,即可知执行兼容性检查的本质:-)

  回复  引用  查看    
#52楼2008-05-27 14:47 | agp001      
学习中
  回复  引用  查看    
#53楼[楼主]2008-05-27 17:50 | Anytao      
@agp001
常来常新:-)

  回复  引用    
#54楼2008-07-30 11:03 | yiyisawa.Liu[未注册用户]
楼主的精神值得敬佩,不好意思再潜水了.学习中.
  回复  引用  查看    
#55楼[楼主]2008-07-31 01:25 | Anytao      
@yiyisawa.Liu
呵呵,欢迎常来看看:-)

  回复  引用  查看    
#56楼2008-08-27 11:40 | YITIAN Studio      
程序员都有挑剔和骄傲的情节。
“在.NET中,一切类型都必须集成自System.Object类型”原文中打错字啦,应该是继承。

说实话我不知道为什么总是推荐用哪个,然后说什么好不好,效率什么的。。。就是一个小小的is和as至于影响效率么?
还有真的有把很不相关的两个类用is或者as搞到一起的么。。。
如果按照这样的思路去学语言会不会有点舍本逐末。

ps:我只看了这一篇,并且我自认也是个新手。还请高手回答我的疑虑。谢谢。
from千冰念

  回复  引用  查看    
#57楼[楼主]2008-08-28 12:38 | Anytao      
@YITIAN Studio
首先谢谢你的指正。

关于is和as实质上是两张模式,在实际的系统中对于类型的判定常常是必须的,因为很多时候你并不清楚接受的参数是否是一个兼容的类型,就像你说的一样两个不相关类型的变量是经常会搞到一起的。
非安全的类型参数或者变量会引起系统灾难,这是类型检查存在的意义,也就是is和as存在的意义,一种实现的手段。

  回复  引用  查看    
#58楼2008-09-15 00:21 | michaellu      
受教。
  回复  引用  查看    
#59楼[楼主]2008-09-18 20:43 | Anytao      
@michaellu
~!~

  回复  引用  查看    
#60楼2008-09-27 11:22 | 棠棠dotNet      
感谢LZ分享,长期关注支持你的新文章。(:
  回复  引用  查看    
#61楼2008-10-06 13:15 | dream one minute      
谢谢分享,学习中。
  回复  引用  查看    
#62楼[楼主]2008-10-06 16:48 | Anytao      
@棠棠dotNet
呵呵,谢谢你的关注:-)

  回复  引用  查看    
#63楼[楼主]2008-10-06 16:48 | Anytao      
@dream one minute
呵呵,欢迎欢迎:-)

  回复  引用  查看    
#64楼2008-12-12 09:17 | tosun      
请问这句话在表述上是不是有点错误哦,反正我在第一次看的时候没有明白过来。

如果结果判断为空,则强制执行类型转换将抛出NullReferenceException异常。


不知道是不是我还没有理解清楚。正在拜读的你文章中。。。

  回复  引用  查看    
#65楼[楼主]2008-12-12 17:54 | Anytao      
--引用--------------------------------------------------
如果结果判断为空,则强制执行类型转换将抛出NullReferenceException异常。
-------------------------------------------------------
呵呵,写的快了点儿,表达欠妥。如果结果判断为空,强制执行类型转换,相当于对null执行操作,则将抛出NullReferenceException异常。

  回复  引用    
#66楼2008-12-17 14:52 | @chenfeng.tang[未注册用户]
LZ,看了你的文章,解释得很清楚,说得很好!
虽然我是第一次接触C#,不过一看就懂,之前我用的是JAVA,
现在感觉C#跟JAVA几乎没什么大的区别,就同is的用法一样,
JAVA里面用的是 instance of,也是用来判断一个对象是否属于一个类的一个事例的.
呵呵,LZ,有机会得好好向你请教请教啊!

  回复  引用  查看    
#67楼[楼主]2008-12-20 17:05 | Anytao      
@@chenfeng.tang
随时恭候。Java和c#在语言特性上有很多类似,但是也存在不少差别,所以了解差别,兼顾共性,会很好。

  回复  引用  查看    
#68楼2009-01-12 17:21 | 赵俊      
看了一下感觉is和as就是用来判断类型是否相同的,我写程序好像都没有用到过,:( 能不能告诉我is和as一般在哪些应用中会用到啊?谢谢。
  回复  引用  查看    
#69楼2009-01-23 00:30 | Done      
请问楼主“任何类型转换为其派生类型时,必须进行显示转换,转换的规则是:(类型名)对象名; ”一个对象能强制转换成它的派生类吗?那这段代码为什么编译不过呢
internal class A
{
//...
}
public sealed class Program
{
public static void Main()
{
object o1 = new object();
A a1 = (A)o1;//把object类型转换成A类型,编译不通过
}
}
什么是类型兼呢,呵呵,谢谢

  回复  引用  查看    
#70楼[楼主]2009-02-02 08:58 | Anytao      
@赵俊
文中已有详细的示例。一般来说,is常做类型兼容检查,而as用来做类型转换:-)

  回复  引用  查看    
#71楼[楼主]2009-02-02 09:07 | Anytao      
@Done
一个对象能强制转换成它的派生类吗?

答案是:能。否则一个违反Liskov替换原则的面向对象语言,何以面见万千程序开发者的颜面:-)

另外,你提供的代码显然是没有问题的,不知为何编译通不过:-)

  回复  引用  查看    
#72楼2009-03-03 17:34 | hhe      
LZ ,你好看了你的文章我有一个疑问:

class a {}
A a = new A();
//object o = new object();
object o =a;

A a1 = o as A;
if (a1==null)
{

}
为什么o=new object()就返回null ,而o=a就不为null
object o=a是不是已经隐士的进行了转换了,new 的为什么不行?

ps: 本人新手

  回复  引用    
#73楼2009-03-03 18:27 | nobodyknow[未注册用户]
@Done
一个对象当然能转换成任何类,引用类型之间的转换,要用as
你用的是啥??是强制类型转换,去看看强制类型转换的使用再说吧

  回复  引用    
#74楼2009-03-03 18:29 | nobodyknow[未注册用户]
@hhe
object o = new object();返回的是null吗???
那o.toString()有怎么解释呢?要知道null.toString()是要砍头的

  回复  引用    
#75楼2009-03-04 09:34 | hazel[未注册用户]
@nobodyknow
砍头,o(>﹏<)o千万别,,我说的是a1 :-)

  回复  引用  查看    
#76楼[楼主]2009-03-04 11:25 | Anytao      
@hhe
@hazel
@nobodyknow
你们的讨论实在太精彩了:-)

基于你的问题,我想还是回到as的规则来了解就一目了然了:

检查对象类型的兼容性,并返回结果,如果不兼容就返回null;
不会抛出异常;
如果结果判断为空,则强制执行类型转换将抛出NullReferenceException异常。

其实A a1 = o as A;时a1是否为null完全取决于类型兼容性检查的结果,你看到的结果也就是类型检查的结果罢了。

  回复  引用  查看    
#77楼2009-03-05 23:37 | anncesky      
--引用--------------------------------------------------
hhe: LZ ,你好看了你的文章我有一个疑问:

class a {}
A a = new A();
//object o = new object();
object o =a;

A a1 = o as A;
if (a1==null)
{

}
为什么o=new object()就返回null ,而o=a就不为null
object o=a是不是已经隐士的进行了转换了,new 的为什么不行?
-------------------------
去看看多态条件

ps: 本人新手
--------------------------------------------------------

  回复  引用  查看    
#78楼2009-03-12 22:35 | 会长      
O(∩_∩)O~:
as 运算符必须用于引用类型或可为 null 的类型;
呵呵,补充一点。

  回复  引用  查看    
#79楼[楼主]2009-03-18 10:36 | Anytao      
@anncesky
??你的问题是

  回复  引用  查看    
#80楼[楼主]2009-03-18 10:48 | Anytao      
@会长
很好的补充

  回复  引用    
#81楼2009-05-05 08:45 | LOVE勇
谢谢楼主的技术公开!
  回复  引用  查看    
#82楼[楼主]2009-05-05 09:42 | Anytao      
@LOVE勇
重在参与:-)




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 704011




相关文章:

相关链接: