2012-09-28 31 views
1

我有以下DBML修改(我使用Linq to SQL作爲DAL)。具有通用工廠模式的IRepository模式

public interface ILinqSQLObject { } 

// these are objects from SQL Server mapped into Linq to SQL 
public partial class NEWDEBT : ILinqSQLObject { } 
public partial class OLDDEBT : ILinqSQLObject { } 
public partial class VIPDEBT : ILinqSQLObject { } 

由於我可以更好地在其他區域操縱我的Linq對象。

我剛剛完成了一個IRepository模式實現。

public interface IDebtManager<T> 
    { 
     IQueryable<T> GetAllDebts(); 
     IQueryable T GetSpecificDebt(System.Linq.Expressions.Expression<Func<T, bool>> predicate); 
     void Insert(T debt); 
     // other methods 
    } 

public class DebtManager<T> : IDebtManager<T> where T : class, ILinqSQLObject 
    { 
     DebtContext conn = new DebtContext(); 
     protected System.Data.Linq.Table<T> table; 

     public DebtManager() 
     { 
      table = conn.GetTable<T>(); 
     } 

     public void Insert(T debt) 
     { 
      throw new NotImplementedException(); 
     } 

     public IQueryable<T> GetSpecificDebt(System.Linq.Expressions.Expression<Func<T, bool>> predicate) 
     { 
      return table.Where(predicate); 
     } 

     public IQueryable<T> GetAllDebts() 
     { 
      return table; 
     } 
    } 

而且工作完美無瑕。但是,有時我不知道,在編譯時,我將使用哪個特定的表。爲此,我嘗試爲我的DebtManager創建一個簡單的通用工廠。

public static class DebtFactoryManager 
{ 

    public static DebtManager<ILinqSQLObject> GetDebtManager(string debtType) 
    { 
     switch (debtType) 
     { 
      case "New Client": 
       return new DebtManager<NEWDEBT>(); 
      case "Old Client": 
       return new DebtManager<OLDDEBT>(); 
      case "VIP Client": 
       return new DebtManager<VIPDEBT>(); 
      default: 
       return new DebtManager<NEWDEBT>(); 
     } 

     return null; 
    } 

} 

但它不起作用。它說我不能'暗示將DebtManager<NEWDEBT>轉換爲DebtManager<ILinqSQLObject>',但是如果NEWDEBT實現ILinqSQLObject,爲什麼編譯器不能識別它?很明顯,我犯了一些錯誤,但我看不到它。

+0

這是實效代碼嗎?我認爲靜態工廠方法缺少名稱。 –

+0

我不小心刪除了它的名字。我只是編輯它。謝謝 – AdrianoRR

回答

0

此錯誤是由泛型不隱式支持協方差的事實造成的;也就是說,將特定的泛型參數類型視爲它的基本類型之一。

解決方法。首先,您可以定義通用DebtManager繼承的非通用DebtManager基類,並返回該基類。其次,你可以定義一個DebtManager實現的通用接口;可以通過在泛型類型參數之前使用關鍵字out將通用接口定義爲協變。

編輯:讓我們回到主要需求。編譯時,您可能不知道需要使用哪種類型的對象,因此您不知道需要哪個庫。那麼,我可能會建議您使用每個數據庫的存儲庫,而不是每個表的存儲庫架構。 DebtManager對任何Linq to SQL類型都是通用的;那麼爲什麼不把這些方法做成通用的,從而允許它們在通話時是通用的?

public interface IRepository<T> where T:class, ILinqSqlObject 
{ 
    IQueryable<TSpec> GetAllDebts<TSpec>() where TSpec : T; 
    IQueryable<TSpec> GetSpecificDebt<TSpec>(System.Linq.Expressions.Expression<Func<TSpec, bool>> predicate) where TSpec : T; 
    void Insert<TSpec>(TSpec debt) where TSpec:T; 
    // other methods 
} 

interface IDebtObject : ILinqSqlObject 

public interface IDebtManager:IRepository<IDebtObject> { } 

public class DebtManager:IDebtManager 
{ 
    DebtContext conn = new DebtContext(); 

    public DebtManager() 
    {    
    } 

    public void Insert<T>(T debt) where T:IDebtObject 
    { 
     throw new NotImplementedException(); 
    } 

    public IQueryable<T> GetSpecificDebt(System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T:IDebtObject 
    { 
     return conn.GetTable<T>().Where(predicate); 
    } 

    public IQueryable<T> GetAllDebts<T>() where T:IDebtObject 
    { 
     return conn.GetTable<T>(); 
    } 

} 
+0

是的,但只有當所有屬性,字段和方法都是隻讀或具有'out'參數時'out'纔有效。 –

+0

@KeithS神聖的人,你是一個天才!你的第一個工作完美無瑕。相信我,我正在努力爲此花費一段時間。這似乎比將界面定義爲通過協同變得更好。有沒有一種情況,有一個協變界面比你的第一個工作更好? – AdrianoRR

+0

那麼第一個解決方法基本上隱藏了這個集合是通用的事實。如果你需要知道該對象是通用類型的(例如,獲取/設置泛型類型的子對象),那麼它不是最好的計劃。在你的情況下,你不知道DebtManager被指向哪個表,除非你以另一種方式跟蹤它,或者反映到類型中並檢查它的通用成員。 – KeithS