日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

Effective C#: Item 3: Prefer the is or as Operators to Casts

發布時間:2023/12/18 C# 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Effective C#: Item 3: Prefer the is or as Operators to Casts 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

Item 3: Prefer the is or as Operators to Casts

C#是強類型語言.我們要盡量避免類型轉換.

有時我們必須要在runtime檢查一個變量的類型.比如有時你要用到一些.Net framework提供的方法,這些方法需要用到System.Object類型的參數.你需要把這些object (方法的參數)向下cast成其他的類型(類或者interface),這時你有兩個基本方式可以選擇,一是使用as操作符,二是使用C語言風格的cast.兩者也可以結合成一個更加保險的方法,就是先用is 操作符來測試類型的轉換,然后再用cast或者as 操作符進行轉換.

正確的選擇應該是使用as操作符來進行類型轉換. as操作符比碰運氣型的cast更加的安全,而且在runtime更加的高效. asis操作符并不能進行所有的用戶定義的類型轉換, 只有當runtime類型和目標類型一致時轉換操作才會成功.它們永遠不會為了滿足程序調用請求而創建一個新的object.

在下例中,你需要把一個object轉換成一個MyType的實例,你可以這樣實現:

????????????????? object o = Factory.GetObject( );<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

?

????????????????? // Version one:

????????????????? MyType t = o as MyType;

?

????????????????? if ( t != null )

????????????????? {

??????????????????????? // work with t, it's a MyType.

????????????????? }

????????????????? else

????????????????? {

??????????????????????? // report the failure.

????????????????? }

也可以這樣寫:

????????????????? object o = Factory.GetObject( );

?

????????????????? // Version two:

????????????????? try

????????????????? {

??????????????????????? MyType t;

??????????????????????? t = ( MyType ) o;

??????????????????????? if ( t != null )

??????????????????????? {

????????????????????????????? // work with T, it's a MyType.

??????????????????????? }

??????????????????????? else

??????????????????????? {

????????????????????????????? // Report a null reference failure.

??????????????????????? }

????????????????? }

????????????????? catch

????????????????? {

??????????????????????? // report the conversion failure.

????????????????? }

第一個方法明顯更加的簡單易讀,而且也沒有try/catchoverhead.代碼更加的高效.我們注意到cast版本不僅要檢查轉換后的object是否為null,還要catch異常.as操作符版本卻不用. 這是因為使用cast, null可以被轉換成任何一種reference類型,但是當應用as操作符在一個null reference上時會返回null. 所以as操作符只需檢查一下返回的reference是否為null, 而不用catch異常.

as操作符和cast操作符最大的不同是如何對待用戶定義的轉換. asis操作符只會檢查被轉換的objectruntime類型,而不做任何其他的工作. 如果這個object不是目標類型,或者不是目標類型的子類型, 操作失敗并終止. cast操作符卻不同,它會把object轉換成目標類型, 這包括所有的numeric轉換, 比如從long轉換成short, object的一些信息就在這種轉換中丟失了.

而且當cast用戶自定義類型時也會有同樣的問題.比如:

????? public class SecondType

????? {

??????????? private MyType _value;

?

??????????? // other details elided

?

??????????? // Conversion operator.

??????????? // This converts a SecondType to

??????????? // a MyType, see item 29.

??????????? public static implicit operator

????????????????? MyType( SecondType t )

??????????? {

????????????????? return t._value;

??????????? }

????? }

假設我們用Factory.GetObject()生成了一個SecondTypeobject,并把它轉換成MyType類型.

????????????????? object o = Factory.GetObject( );

?

????????????????? // o is a SecondType:

????????????????? MyType t = o as MyType; // Fails. o is not MyType

?

????????????????? if ( t != null )

????????????????? {

??????????????????????? // work with t, it's a MyType.

????????????????? }

????????????????? else

????????????????? {

??????????????????????? // report the failure.

????????????????? }

?

????????????????? // Version two:

????????????????? try

????????????????? {

??????????????????????? MyType t1;

??????????????????????? t = ( MyType ) o; // Fails. o is not MyType

??????????????????????? if ( t1 != null )

??????????????????????? {

????????????????????????????? // work with t1, it's a MyType.

??????????????????????? }

??????????????????????? else

??????????????????????? {

????????????????????????????? // Report a null reference failure.

??????????????????????? }

????????????????? }

????????????????? catch

????????????????? {

??????????????????????? // report the conversion failure.

????????????????? }

兩個版本都會失敗.但是cast卻執行了用戶定義的轉換.這種假象使你認為cast成功了.但實際上它是失敗的,因為編譯器會根據編譯時object的類型來生成代碼.編譯器對運行時object的類型一無所知.它只是把o當作System.Object的一個實例.編譯器沒有發現從System.ObjectMyType可行的轉換.它檢查System.ObjectMyType的定義,因為缺少用戶定義的轉換信息,編譯器生成代碼來檢查o的運行時的類型,然后檢查它是不是MyType類型.因為oSecondType類型,所以轉換失敗.編譯器并不檢查o在運行時的類型是否可以轉換成MyType類型.

如果你想讓轉換成功,可以這樣寫代碼:

????????????????? object o = Factory.GetObject( );

?

????????????????? // Version three:

????????????????? SecondType st = o as SecondType;

????????????????? try

????????????????? {

??????????????????????? MyType t;

??????????????????????? t = ( MyType ) st;

??????????????????????? if ( t != null )

??????????????????????? {

????????????????????????????? // work with T, it's a MyType.

??????????????????????? }

??????????????????????? else

??????????????????????? {

????????????????????????????? // Report a null reference failure.

??????????????????????? }

????????????????? }

????????????????? catch

????????????????? {

??????????????????????? // report the failure.

????????????????? }

你永遠也不應該寫這樣丑陋的代碼,但這也是一個常見的問題.盡管你永遠不應該寫這樣的代碼,但你可以用System.Object來當作一個進行轉換操作的function的參數,比如:

??????????? object o = Factory.GetObject( );

?

??????????? DoStuffWithObject( o );

?

??????????? private void DoStuffWithObject( object o2 )

??????????? {

????????????????? try

????????????????? {

??????????????????????? MyType t;

??????????????????????? t = ( MyType ) o2; // Fails. o is not MyType

??????????????????????? if ( t != null )

??????????????????????? {

????????????????????????????? // work with T, it's a MyType.

??????????????????????? }

??????????????????????? else

??????????????????????? {

????????????????????????????? // Report a null reference failure.

??????????????????????? }

????????????????? }

????????????????? catch

????????????????? {

??????????????????????? // report the conversion failure.

????????????????? }

??????????? }

用戶自定義的轉換只作用于編譯時object的類型,而不時運行時的類型. 至于運行時是否存在o2MyType類型的轉換, 編譯器不知道也根本不關心. 但當st類型不同時,這個語句有著不同的表現:

t = ( MyType ) st;

上面的語句會調用用戶自定義的轉換,從而造成轉換成功的假象. 但使用as操作符的語句卻有著一致的表現.所以應該盡量的使用as操作符.如下面的語句:

t = st as MyType;

?

事實上,如果stMyType之間不存在繼承關系的話,而是通過一個用戶自定義的轉換來進行類型轉換,那么編譯器會報告一個錯誤.

現在你知道了應該盡可能的使用as操作符.但也有一些情況不能使用它.as操作符不能作用于value type.下面的這個語句不會通過編譯:

object o = Factory.GetValue( );

????????????????? int i = o as int; // Does not compile.

因為int是值類型,永遠不能為null.那么如果o不是整數類型的話, i里面應該存什么值呢? 所以你不能使用as操作符.你可以用下面這種變通的方式:

????????????????? object o = Factory.GetValue( );

????????????????? int i = 0;

????????????????? try

????????????????? {

??????????????????????? i = ( int ) o;

????????????????? }

????????????????? catch

????????????????? {

??????????????????????? i = 0;

????????????????? }

但你不必一定這樣一來做,不要忘了is操作符,你可以在轉換之前先判斷o的類型:

????????????????? object o = Factory.GetValue( );

????????????????? int i = 0;

????????????????? if ( o is int )

??????????????????????? i = ( int ) o;

如果o不是整數類型,那么is操作符返回false. is操作符作用于null arguments上時,永遠返回false;

但你應該只在你不能使用as操作符轉換類型時使用is,否則就是重復的, 比如:

????????????????? // correct, but redundant:

????????????????? object o = Factory.GetObject( );

?

????????????????? MyType t = null;

????????????????? if ( o is MyType )

??????????????????????? t = o as MyType;

上面的代碼和下面的代碼是等效的:

????????????????? // correct, but redundant:

????????????????? object o = Factory.GetObject( );

?

????????????????? MyType t = null;

????????????????? if ( ( o as MyType ) != null )

??????????????????????? t = o as MyType;

可以看出,進行了兩次轉換,低效而且重復.如果你已經決定了要使用as操作符來轉換類型,那么只需檢查返回值是否為null就可以了.

現在你已經明白了as, iscast,那么foreach循環用的是什么操作符呢?

??????????? public void UseCollection( IEnumerable theCollection )

??????????? {

????????????????? foreach ( MyType t in theCollection )

??????????????????????? t.DoStuff( );

??????????? }

foreach用的實際上是cast操作符.上面的代碼可以重寫成下面的代碼:

??????????? public void UseCollection( IEnumerable theCollection )

??????????? {

????????????????? IEnumerator it = theCollection.GetEnumerator( );

????????????????? while ( it.MoveNext( ) )

????????????????? {

??????????????????????? MyType t = ( MyType ) it.Current;

??????????????????????? t.DoStuff( );

????????????????? }

??????????? }

這是因為foreach要用cast來支持value typereference type. 如果使用as操作符的話,foreach語句仍表現相同的行為,但會拋出BadCastException,因為as不能作用于值類型上.

因為IEnumerator.Current返回一個System.Object類型的object,而這個object不具備轉換操作,所以并不能用于這個測試. SecondType類型的collection也不能用于UseCollection()因為轉換會失敗. Foreach語句并不檢查collectionobject的運行時類型是否支持這種轉換,它只檢查IEnumerator.Current所返回的System.Object類型是否支持到目標類型(本例中的MyType)之間的轉換.

最后,有時你想知道一個object確切的類型,而不只是關心這個object是否可以轉換成目標類型. 因為as操作符對于所有從目標類型繼承而來的類型的轉換都返回true. GetType()方法返回object運行時的類型,它比as或者is操作符提供的測試都要更嚴格. 它返回的是object的確切類型.

再看一下UseCollection():

??????????? public void UseCollection( IEnumerable theCollection )

??????????? {

????????????????? foreach ( MyType t in theCollection )

??????????????????????? t.DoStuff( );

??????????? }

如果你創建一個叫NewType的類,這個類繼承MyType,那么NewType objectscollection也可以在UseCollection()中很好的工作.

????? public class NewType : MyType

????? {

??????????? // contents elided.

????? }

如果你的意圖是寫出一個可以使用所有MyType類型(自身或繼承而來)function,這沒有什么.但如果你的意圖是寫一個只接受MyType類型自身的function的話,你就要用確切的類型來進行比較. 在本例中,你可以在foreach循環里做. 知道運行時確切的類型只有在做equality測試時是非常重要的.在大多數其他的情況下,asis操作符提供的isinst比較是語法上正確的.

好的OO經驗告訴我們要盡量避免類型的轉換,但有時類型轉換是必需的.在這種情況下,盡量的使用asis操作符來表達你的意圖. 不同的類型強制轉換有不同的規則,asis卻在絕大多數情況下都是正確的,而且它們只有在object是正確的類型時才轉換成功. Cast操作符會帶來一些副作用,而且轉換的成功與失敗往往出乎意料.

??

?

?

本系列文章只是作者讀書筆記,版權完全屬于原作者 (Bill Wagner),任何人及組織不得以任何理由以商業用途使用本文,任何對本文的引用和轉載必須通知作者:zphillm@hotmail.com

轉載于:https://www.cnblogs.com/ZphillM/archive/2005/08/06/208713.html

總結

以上是生活随笔為你收集整理的Effective C#: Item 3: Prefer the is or as Operators to Casts的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。