2009-02-18 43 views
1

我有以下類(修剪以僅顯示基本結構):通用方法拾取基類的類型

public abstract class BaseModel { 
    public bool PersistChanges() { 
     // Context is of type "ObjectContext" 
     DatabaseHelper.Context.SafelyPersistChanges(this); 
    } 
} 

public static class ObjectContextExtensions { 
    public static bool SafelyPersistChanges<T>(this ObjectContext oc, T obj) { 
     // Persist the object using a transaction 
    } 
} 

[Persistent("LEADS")] 
public class Lead : BaseModel { 
    // Extra properties 
} 

public class LeadsController : Controller { 
    public ActionResult Save(Lead lead) { 
     lead.PersistChanges() 
    } 
} 

類從BaseModel,其中包含一個方法來導出使用事務將對象的更改保存到數據庫中。我用擴展方法實現了事務持久化。問題是,通過傳遞這在我的BaseModelSafelyPersistChanges,對擴展方法的一般T設定爲BaseModel。但是,由於BaseModel未標記爲持久對象(不能這樣做),ORM框架將引發異常。

實施例:

Lead lead = LeadRepository.FindByNumber(2); 
lead.SalesmanNumber = 4; 
// Calls "ObjectContextExtensions.SafelyPersistChanges<BaseModel>(BaseModel obj)" 
// instead of "ObjectContextExtensions.SafelyPersistChanges<Lead>(Lead obj)" 
lead.PersistChanges(); 

上述塊引發以下例外:

無法爲沒有持久屬性類型 'SalesWeb.Data.BaseModel' 創建映射。

任何想法?

回答

3

擴展方法在編譯時被靜態綁定。在SafelyPersistChanges被調用的時候,這被鍵入爲BaseModel,因此是你的異常。爲了獲得你想要的行爲,你需要做一個醜陋的if語句,並且強制轉換派生類。

使PersistChanges成爲抽象方法。然後使用完全相同的代碼在派生類中實現調用。

public class Lead { 
    public override bool PersistChanges() { 
     // Context is of type "ObjectContext" 
     DatabaseHelper.Context.SafelyPersistChanges(this); 
    } 
} 

現在,這將正確地領導

+0

謝謝!它會產生代碼重複,但我想這只是我必須作出的犧牲。從好的方面來說,它使模型有機會在堅持自己之前執行其他操作。 – 2009-02-18 21:14:34

1

我會設計這種不同的方式,使「公共布爾PersistChanges()」調用一個虛擬方法,這是在每個子類中重寫。

0

所以,你希望有一個「單一」的實施,是改變對調用者已知的類型。聽起來像是泛型的工作。

public static bool PersistChanges<T>(this T source) 
    where T : BaseModel 
{ 
     // Context is of type "ObjectContext" 
//static property which holds a Context instance is dangerous. 
     DatabaseHelper.Context.SafelyPersistChanges<T>(source); 
} 
0

你可以解決這個使用curiously recurring template pattern

// change your code to this 

public abstract class BaseModel<TDerived> where TDerived : BaseModel 
{ 
    public bool PersistChanges() { 
     // Context is of type "ObjectContext" 
     DatabaseHelper.Context.SafelyPersistChanges((TDerived)this); 
     //           ^
     // note the cast here: -----------------------| 
    } 
} 

public class Lead : BaseModel<Lead> { } 

// the rest of your code is unchanged 

這樣做是可以的,但我可能只是跟隨其他建議,並使用虛擬方法。