2011-02-17 236 views
5

在試圖實現存儲庫模式時,我遇到了一個我所關心的小問題,實際上隱藏了更大的問題。鑄造,泛型和子類型

我有一個DatabaseEntity <T>,我正在使用它來處理所有基本的CRUD操作,並且所有其他需要存儲在數據庫中的類將從其中下載。對於直接從它繼承的類來說,它工作得很好,但是當它與具有中間父類的類一起使用時,我遇到了問題。

假設我有其他三個班,家長,ChildA和ChildB和和繼承的樣子:

DatabaseEntity
                  |
       家長
        |             |
ChildA ChildB

還假定DatabaseEntity <T>具有以下簽名的方法:

public static T FindBy(int id) 

我遇到的問題是,當我嘗試類似:

ChildA Foo = ChildA.FindBy(SomeID); 

我得到一個編譯器錯誤,告訴我沒有從Parent到ChildA的隱式轉換。這是因爲Parent是將類型參數傳遞給ChildA和ChildB的DatabaseEntity的類。簡單解決方法我認爲,只需向Parent添加一個類型參數,然後傳遞適當的類型。只需等待一秒,然後我必須在任何時候使用Parent來明確定義子類型,這會破壞任何多態性。不,再次想到也許這不是一個很好的解決方案。

我想我可以只刪除該類型參數在類DatabaseEntity本身,讓每個方法需要一個類型參數,但後來我不得不這樣做:

ChildA Foo = ChildA.FindBy<ChildA>(SomeID); 

雖然可以編譯,它似乎不太乾淨,當然需要更多的打字。 Visual Studio中問,如果我缺少強制,雖然其真正的我可以投我的第一個例子中其唯一一個時間的問題之前,我不小心輸入了:

ChildB Foo = (ChildB) ChildA.FindBy(SomeID) 

我不與任何特別高興我想到的解決方案迄今爲止,我希望這裏有人能指出我錯過的優雅的一個。

+0

哪個.Net版本受到限制? – Adrian 2011-02-17 02:55:04

+0

您需要一個支持LINQ操作的ORM,那麼您可以使用`OfType `來完成父代到孩子之間的轉換。 – RPM1984 2011-02-17 03:11:36

回答

5

我認爲製作Parent是一個通用的類是要走的路。您沒有解釋在您的示例中T類型的用途是什麼,但我想您希望它是實體的實際類型,因此您的Parent將繼承Entity<Parent>

你仍然可以寫在這種情況下多態代碼 - 你只需要使用泛型:

static void Foo<T>(Parent<T> p) where T : Parent<T> 
{ 
    Parent<T> entity = p.Find(); 
} 

這種方法可以既ChildAChildB被調用。唯一棘手的方面是,你不能真正創造的Parent<Parent<...>>一個實例(由於該點必須與多個嵌套Parent<...>類型來代替),但你可以寫的財產以後這樣的:

class ParentFix : Parent<ParentFix> { } 

..然後你可以將ParentFix的實例也傳遞給Foo方法。

2

我知道這不是您正在尋找的答案,但我會推薦使用實體現成的ORM,如實體框架4.它支持開箱即用的繼承,它是基本的,基礎的用法存儲庫。

我覺得如果你試圖自己推出這個東西,你會感到很痛苦。

+0

我實際上使用NHibernate,我試圖設置我的DatabaseEntity類,所以我不必重複添加非常基本的查找/刪除/保存爲我的每個類調用NHibernate的方法。 NHibernate已經完成了所有繁重的工作:) – Trajanus 2011-02-17 20:58:02

0

我很抱歉,如果我沒有在這裏得到更大的畫面,但你可以 DatabaseEntity<T>一個單獨的通用類(靜態的可能),沒有獲得來自它的 Parent

這種安排將允許使用您可能具有的任何類的所有使用DatabaseEntity<T>定義的CRUD操作。

請注意:如果我錯過了某些明顯的東西,請不要激怒我,我寧願爲了澄清一些東西,以便我可以更好地學習。