2012-01-18 60 views
3

這裏是我的工作的代碼示例:爲什麼Visual Studio的IntelliSense不適用於派生類?

BaseClass class1; 
    if (userControl.Key == 100) 
    { 
     class1 = new DerivedClass1(); 

     //This does not work, but it seems like it should 
     class1.PropertyInDerivedClass1 = 7 

     //This does work, but why should I have to cast something that I just instantiated? 
     ((DerivedClass1)class1).PropertyInDerivedClass1 = 7; 
    } 
    else 
     class1 = new DerivedClass2(); 

有什麼我可以做,以便能夠更輕鬆地訪問派生類中的屬性和方法?

+0

按照從@DaveShaw保留關鍵字的響應爲C#http://msdn.microsoft.com/en-us/library/x53a06bb.aspx – Lloyd

+3

是的,可以。您可以使用派生類的類型的變量。 – millimoose

+0

您要求的內容需要進行某種數據流分析,以將強制類型轉換爲編譯器可以確定的內容,即分配給變量的當前值,並使語言更加複雜。這聽起來像是當語言設計者只需在'if'塊中擁有派生類型的局部變量時就不會去的努力。 – millimoose

回答

3

如果您希望使用派生類的變量,則需要使用具有該特定類型的引用來解決它們。

BaseClass obj1; 
DerivedClass dc = new DerivedClass(); 
dc.DerivedPropertyToAccess = value; 
obj1 = dc; 

總之,在您的示例代碼錯誤是訪問使用與所述基類類型,而不是派生的類的引用的屬性。

2

它不起作用的原因是因爲您試圖訪問DerivedClass1的屬性BaseClass,但它們不存在於該類中。僅僅因爲存儲在變量class1中的對象是包含屬性的類型的,並不意味着您可以直接訪問這些屬性。以這種方式訪問​​它們的唯一方法是指定class1DerivedClass1。因此,無論你要投它,或做類似:

BaseClass class1; 
if (userControl.Key == 100) 
{ 
    DerivedClass1 dClass1 = new DerivedClass1(); 

    // This will now work 
    dClass1.PropertyInDerivedClass1 = 7; 

    class1 = dClass1; 
} 
else 
    class1 = new DerivedClass2(); 
1

你可以只使用派生類型的臨時變量:

BaseClass baseObj; 
if (…) 
{ 
    var derivedObj = new DerivedClass1(); 
    baseObj = derivedObj; 
    derivedObj.DerivedProperty1 = "foo"; 
} 
else 
{ 
    // Rinse, lather, repeat 
} 

或者,在具體的例子,你可以使用對象初始化劑:

BaseClass baseObj; 
if (…) 
{ 
    baseObj = new DerivedClass1 { 
     DerivedProperty1 = "foo" 
    } 
} // etc… 
2

的C#智能感知使用相同*靜態分析,因爲編譯器

您的代碼行:

class1.PropertyInDerivedClass1 = 7 

不給你的智能感知,因爲它不工作。這不是有效的C#,因爲class1的編譯時間類型是BaseClass,並且它沒有該屬性。

1

自動完成不會使用派生類成員填充,因爲class1是BaseClass類型的變量。它不知道你實際上正在創建和分配存儲在對BaseClass對象的引用中的派生類型。

我建議創建一個新的本地副本派生類型,將其分配給您的原始類型BaseClass的變量,但使用本地副本,使您的派生唯一函數調用。

BaseClass class1; 
if (userControl.Key == 100) 
{ 
    var derivedObject = new DerivedClass1(); 
    class1 = derivedObject; 

    //This will now work 
    derivedObject.PropertyInDerivedClass1 = 7 
} 
else 
    class1 = new DerivedClass2(); 
12
  1. 選擇一個素不相識的人。讓他們吃一把劍。
  2. 隨機挑選一個劍形吞食者。讓他們吃一把劍。

第二個結果是所有的娛樂。在血液,訴訟和最終監禁的第一。

當然,當然,隨機的人可能是一個劍吞食者,但如果你不知道他們是那麼你不能安全地讓他們吃劍。除非通過SwordSwallower引用來處理它們,否則編譯器將不會讓Person類的實例吃劍。

+1

+1,用最少的代碼最有意義。 – Rotem

+0

@Rotem雖然我不清楚初級開發者在當前經濟環境下的初級開發者的相對成本。 ;) –

1

考慮這種情況:

// 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關鍵字也是一個信號,表示您知道自己在做什麼,並對任何不正確的事情承擔責任。

希望幫助

相關問題