国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

C#中 As 和強制轉換的總結

2019-11-06 06:22:20
字體:
來源:轉載
供稿:網友

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.    public class Foo1 : Foo    {        PRivate Logger _value;        /// <summary>        /// 隱式自定義類型轉換。                /// </summary>        /// <param name="foo1"></param>        /// <returns></returns>        public static implicit Operator 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 as int;                 //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 is int){    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

Jackson Huang

關于作者:

[作者]: JK_Rush從事.NET開發和熱衷于開源高性能系統設計,通過博文交流和分享經驗,歡迎轉載,請保留原文地址,謝謝。[出處]:http://www.cnblogs.com/rush/[本文基于]:署名-非商業性使用 3.0許可協議發布,歡迎轉載,演繹,但是必須保留本文的署名JK_Rush(包含鏈接),且不得用于商業目的。如您有任何疑問或者授權方面的協商,請與我聯系。

分類: [02] C#好文要頂 關注我 收藏該文 JK_Rush關注 - 5粉絲 - 1418 榮譽:推薦博客+加關注 14 0 ?上一篇:裝飾者(Decorator)?下一篇:您不能不知的ToString()方法posted @ 2011-05-13 21:05 JK_Rush 閱讀(17528) 評論(13)編輯 收藏評論列表  #1樓2011-05-13 21:20 Create Chen  as比is性能好根本原因說白了是它比is少執行類型檢查
123456System.Object o =new System.Object(); if (o is SomeMyClass)  //第一次執行類型檢查{SomeMyClass myClass = (SomeMyClass)o;  //第二次執行類型檢查}
CLR執行了兩次類型檢查,因為這樣,所以會降低性能.所以有了as操作符, 它可以避免執行兩次類型檢查. 如果兼容, as會返回一個指向同一個對象的指針, 不兼容的話就返回null, 上面的代碼用as操作符寫就如下:
1234567System.Object o =new System.Object(); SomeMyClass myClass = oas SomeMyClass;//只執行一次類型檢查if (myClass != null){    //........}
和is一樣,as也不會拋出異常支持(0)反對(0)  #2樓[樓主]2011-05-13 21:25 JK_Rush  @Create Chen是的,一般考慮到效率情況應該減少as-is一起使用。支持(0)反對(0)  #3樓2011-05-13 22:23 水牛刀刀  "編譯時類型和運行時類型"這種說法似乎不妥,你似乎是想說“變量聲明類型”和“對象的類型”。支持(0)反對(0)  #4樓2011-05-14 09:40 菜鳥進博客園眼花撩亂  
引用JK_Rush:@Create Chen是的,一般考慮到效率情況應該減少as-is一起使用。
VS對項目點右鍵 選擇"代碼分析"的時候as 和 is一起用就會顯示成警告支持(0)反對(0)  #5樓2011-05-14 10:08 阿龍  很多時候,不在乎這點性能,也不乎它拋異常。該拋異常時就拋異常,不怕的。支持(0)反對(0)  #6樓[樓主]2011-05-14 10:25 JK_Rush  @菜鳥進博客園眼花撩亂您指的是VS在添加TFS之后的代碼分析功能嗎?支持(0)反對(0)  #7樓2011-05-14 17:10 菜鳥進博客園眼花撩亂  @JK_Rush我記得在公司的電腦上解決方案資源管理器里面 對著項目點右鍵 就有代碼分析。我經常以分析就出幾百個警告,包括命名不規范的警告,大小寫不規范的警告。可是剛在自己電腦上試了,卻沒這個選項。不知道是不是VS版本的區別,或者這是一個插件功能支持(0)反對(0)  #8樓[樓主]2011-05-14 18:53 JK_Rush  @菜鳥進博客園眼花撩亂你公司電腦安裝了Team Foundation Server吧!支持(0)反對(0)  #9樓2011-05-15 08:56 菜鳥進博客園眼花撩亂  @JK_Rush沒有裝TFS記得好像是微軟的2款代碼檢測插件。非常嚴格,連私有字段 屬性 私有方法 公有方法 的順序都不能錯支持(0)反對(0)  #10樓[樓主]2011-05-15 10:56 JK_Rush  @菜鳥進博客園眼花撩亂有一個微軟的代碼插件的確比較嚴格:StyleCop,用它分析代碼會出現很多警告。支持(0)反對(0)  #11樓2015-03-12 14:52 conanVista  https://msdn.microsoft.com/zh-cn/library/ms182271.aspx如果在執行實際的強制轉換之前,使用 C# is 運算符來測試強制轉換是否將成功,請考慮轉為測試 as 運算符的結果。 后者可以提供相同的功能,但不需要由 is 運算符執行的隱式強制轉換操作。看起來 is 實現是 try { ? = (T)obj } catch { }as 比 is 好。支持(0)反對(0)  #12樓2015-03-27 11:45 njl_041x  研究的有深度,果斷關注大牛!越是看到像你們這樣的大牛,越覺得自己學的膚淺~支持(0)反對(0)  #13樓2015-07-13 10:11 佯林  直接在快速啟動里面輸入“代碼分析”既可啟動那個窗口
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 赤峰市| 南安市| 巴林左旗| 封开县| 贵州省| 桓台县| 花垣县| 赤水市| 资溪县| 东阳市| 双辽市| 库伦旗| 巴东县| 浙江省| 湖北省| 阜城县| 永兴县| 策勒县| 阿城市| 香格里拉县| 寿阳县| 阳新县| 济源市| 大宁县| 白河县| 隆林| 平果县| 平昌县| 尼玛县| 红安县| 阿拉善左旗| 高淳县| 会宁县| 炉霍县| 舞钢市| 凌云县| 义乌市| 本溪| 灵山县| 灵寿县| 湟中县|