2014-03-12 70 views
2

假設我有接口IApple和實現它的類Apple。另外,我有幾個班擴展AppleSpartanAppleGreenApple,等..)將對象動態投射到正確的子類

現在,我有以下功能將處理加入蘋果到我的數據庫:

public void CreateApple(IApple apple) 
{ 
    ... 

    db.Apples.Add(apple); // This will take an object of type Apple, or ANY of its sub-types 
    db.SaveChanges(); 
} 

的問題是db.Apples.Add(apple);將爲下列編譯時錯誤

Argument 1: cannot convert from 'IApple' to 'Apple' 

所以我需要它傳遞給Add()前投apple爲適當的類型。我可以通過使用if語句並根據某些屬性將apple轉換爲適當的類型來實現,但是我不希望每次在將來添加新的子類時都必須添加新的情況。

我覺得我在這裏錯過了一些微不足道的東西。有沒有更優雅的方式來做到這一點?任何幫助,將不勝感激。

+3

一般提示 - 如果您需要沮喪,您的設計可能是錯誤的。 –

+0

您是否嘗試將其轉換爲「Apple」? 'db.Apples.Add((Apple)apple);'EF應該在'Add'方法中正確地找出實際的類型。 – MarcinJuraszek

+0

@MarcinJuraszek你是對的。我試過了,它就是這麼做的。如果您將此作爲答案發布,我會接受它。謝謝! – Sadiq

回答

3

您可以將它投射到Apple。 EF會找出實際的類型正確內Add方法:

db.Apples.Add((Apple)apple); 

更新

正如@AntP提到的,你可以通過改變方法簽名避免鑄造接受Apple,而不是IApple

public void CreateApple(Apple apple) 
{ 
    ... 

    db.Apples.Add(apple); 
+2

問題 - 如果你只是想將其轉換爲Apple,除非你的目標是鼓勵異常,否則讓'CreateApple'接受一個'IApple'有什麼意義?爲什麼不用'CreateApple(蘋果蘋果)'而不是?至少可以在調用者中進行投射並避免誤導界面定義。 –

+0

@AntP你應該問薩迪克。 – MarcinJuraszek

+0

不,我應該問你,因爲你發佈這個答案顯然不能解決問題中的根本問題。 –

3

如果CreateApple的唯一目的是將其保存到只接受Apple S中的資料庫,然後只需更改簽字: E:

public void CreateApple(Apple apple) 
{ 
    ... 

    db.Apples.Add(apple); // This will take an object of type Apple, or ANY of its sub-types 
    db.SaveChanges(); 
} 

如果在CreateApple使用接口的原因是沒有對執行情況的相關性,那麼該模型,如果你內部需要情況下的Apple打破。

另一種選擇是創建一個新的AppleIApple只是映射:

public void CreateApple(IApple apple) 
{ 
    Apple newApple = new Apple() 
    { 
     Color = apple.Color, 
     Variety = apple.Variety, 
     ... 
    } 

    db.Apples.Add(newApple); 
    db.SaveChanges(); 
} 

這樣你仍然鬆耦合並且可以使用不同實施IApple無需更改存儲庫代碼。