考慮這種情況:
// This decides what derived class to return depending on parameters you pass in
FunkyBase funky = FunkyFactory.Create("A");
如果編譯器做了一些分析,以確定funky
總是FunkyDerivedA
的基礎上你傳遞,隨後的兩段代碼是緊密耦合。此代碼是說:「我知道這是FunkyBase
或從中派生出來的東西,但這就是我所知道的,所以不要給我任何不在該基類上的選項。如果Visual Studio和.NET編譯器幫忙,給你所有的方法和屬性FunkyDerivedA
,那麼你可以這樣做:
public class FunkyDerivedA : FunkyBase
{
public SomeProperty { get; set; }
}
///// SNIP /////
FunkyBase funky = FunkyFactory.Create("A");
funky.SomeProperty = 7;
然後一切正常,因爲這是你正在使用的實際對象。但是,然後一個美好的一天有所改變,你想切換到FunkyDerivedB
,忘記該屬性不存在於該類。
public class FunkyDerivedA : FunkyBase
{
public SomeProperty { get; set; }
}
// notice it doesn't have the same property
public class FunkyDerivedB : FunkyBase
{
}
///// SNIP /////
// Danger, Will Robinson!
FunkyBase funky = FunkyFactory.Create("B");
funky.SomeProperty = 7;
在這一點上,事情可能會以非常不明顯的方式失敗。投射是你的信號,你知道你在做什麼。這是對您或任何維護您的代碼的人的提醒,即您正在對您獲得的對象的類型(在本例中爲工廠方法)做出假設,並且在更改此代碼時應小心謹慎。
現在,這並不意味着C#不能做你在問什麼。它可以在一定程度上。
從.NET 3.0中,var
關鍵字(見the MSDN article)讓你放棄聲明類型:
var funky = new FunkyDerivedA();
智能感知和編譯時類型檢查的工作,它只是計算出的類型是什麼基於方法的返回類型。請注意,在我上面的工廠示例中,如果Create
方法剛剛返回基類,那麼這將是該類型。它不會根據對調用樹的分析或類似的東西將它轉換爲更派生的類。
從.NET v4.0開始,您可以使用dynamic
(請參閱the MSDN article)關鍵字,該關鍵字放棄編譯時類型檢查,以便讓您按照自己的意願進行操作。當然,如果你弄錯了,你會得到一個運行時異常(不是編譯時錯誤),因爲它在運行時解決,而不是編譯時。同樣,Intellisense也不起作用,所以要確保您知道對象是什麼以及可用的成員。
另請注意,與鑄造一樣,dynamic
關鍵字也是一個信號,表示您知道自己在做什麼,並對任何不正確的事情承擔責任。
希望幫助
按照從@DaveShaw保留關鍵字的響應爲C#http://msdn.microsoft.com/en-us/library/x53a06bb.aspx – Lloyd
是的,可以。您可以使用派生類的類型的變量。 – millimoose
您要求的內容需要進行某種數據流分析,以將強制類型轉換爲編譯器可以確定的內容,即分配給變量的當前值,並使語言更加複雜。這聽起來像是當語言設計者只需在'if'塊中擁有派生類型的局部變量時就不會去的努力。 – millimoose