2014-11-06 120 views
0

的類型時,當我運行以下返回子類:C#類型轉換指定基類

ParentClass foo = serializer.Deserialize(xmlReader) as ParentClass;

xmlReader加載的XML文檔是ParentClass繼承的類型。在調試器中檢查時,foo顯示爲繼承類的實例,而不是父類。當然,繼承類也是類型ParentClass,但爲什麼as關鍵字具有這種行爲?爲什麼C#不去掉所有不需要轉換爲ParentClass的對象信息。

這不是問題,但或多或​​少是出於好奇的問題。

+2

如果它是一個ChildClass,那麼你將在調試器中看到,你只是將它轉換成一個'ParentClass'而不是轉換它,它仍然是一個'ChildClass'並且可以退回。 – 2014-11-06 17:23:01

+0

因爲它實際上是在內存中鍵入'ChildClass'的引用。演員陣容不會改變這一點。 – 2014-11-06 17:28:31

+0

所以「as」實際上不會以任何方式修改對象?它只是驗證給定一個對象的引用,繼承結構是兼容的? – Tim 2014-11-06 17:34:21

回答

1

對象本身沒有被修改,這就是爲什麼對象的類型仍然在調試器中顯示爲「ParentClass」的原因。

考慮下面的例子,我認爲這是例證性的。你認爲在這裏輸出到控制檯是什麼?

class Program 
{ 
    public class ParentClass 
    { 
     public virtual void foo() 
     { 
      Console.WriteLine("parent.foo"); 
     } 

     public virtual void bar() 
     { 
      Console.WriteLine("parent.bar"); 
     } 
    } 

    public class InheritedClass : ParentClass 
    { 
     public new void foo() 
     { 
      Console.WriteLine("inherited.foo"); 
     } 

     public override void bar() 
     { 
      Console.WriteLine("inherited.bar"); 
     } 
    } 

    static void Main(string[] args) 
    { 
     var inherited = new InheritedClass(); 
     var parent = inherited as ParentClass; 
     var d = parent as dynamic; 

     parent.foo(); 
     inherited.foo(); 
     d.foo(); 

     parent.bar(); 
     inherited.bar(); 
     d.bar(); 

     Console.Read(); 
    } 
} 

只有一個對象被創建,然後它會創建兩個引用:一個繼承的靜態類型,和一個與「動態」類型。所有引用引用同一個對象的情況都可以通過調用「bar」調用「InheritedClass.bar」來實現,而不管靜態類型如何(運行時類型始終相同)。但是,請注意使用「覆蓋」和「新」之間的區別:您將看到「parent.foo()」調用「ParentClass.foo」方法。這是因爲「父」變量是靜態類型「ParentClass」類型,所以C#編譯器發出IL指令來調用「ParentClass」上的方法。您可以進一步看到「動態」類型引用仍然調用「InheritedClass.foo」,因爲動態類型在運行時解析,並且這解析爲實際運行時類型,即「InheritedClass」。

編輯 @InBetween有一個重要的區別,我沒有考慮。在從值類型轉換爲引用類型(反之亦然)的情況下,新對象實際創建,因爲新內存必須分別在堆或堆棧上分配(「裝箱」過程)。當然,部分由於這個原因,struct和其他值類型不支持虛擬方法。

+0

謝謝。這絕對清除了我的問題。 – Tim 2014-11-06 18:48:33

1

as只能執行參考轉換,可空轉換和裝箱轉換。它不會執行任何其他類型的轉換,如用戶定義的轉換。

在你的情況下,它執行兼容的參考轉換;對象保持不變,你只是改變參考。

但是as可以在某種意義上「修改」一個對象,例如,我認爲你說的時候,例如,裝箱不僅僅是簡單地轉換引用。

var o = 1 as object; 

o是一個產品總數不同的對象比整數1

重要的是要注意,雖然在任何成功的as轉換GetType()仍然會返回原來的類型,是轉換運算符的一般行爲的對象是很重要的。

+0

+1,關於拳擊/拆箱非常好。 – McGarnagle 2014-11-06 18:06:03

+0

我看不出如何考慮裝箱修改。 – usr 2014-11-07 15:18:33

+0

@usr:引用轉換更改引用的* type *,但它指向的對象保持不變。當裝箱*值類型*你正在包裝一個'System.Object'內的值並存儲它*其他地方*(託管堆,雖然這是障礙sepcific);這意味着你有一個完全不同的對象的參考。 – InBetween 2014-11-07 15:22:46