2014-03-24 44 views
7

我試圖創建一個通用的數據檢索過程。我目前的工作,但有一部分似乎不正確,我希望有一個更好的方法來實現它。T實現接口的通用方法<T>

這樣的想法是,我有類數據庫中的每個表,這裏是一個類的實例:

public class CMCGRGRGROUP : IFacetsObject<CMCGRGRGROUP> 
{ 
    public int GRGR_CK { get; set; } 
    public string GRGR_NAME { get; set; } 
    public string GRGR_ADDR1 { get; set; } 

    public IEnumerable<CMCGRGRGROUP> ToObject(DataTable table) 
    { 
     return table.AsEnumerable().Select(row => 
     { 
      return new CMCGRGRGROUP 
      { 
       GRGR_CK = Convert.ToInt32(row["GRGR_CK"]), 
       GRGR_NAME = row["GRGR_NAME"].ToString(), 
       GRGR_ADDR1 = row["GRGR_ADDR1"].ToString() 
      }; 
     }); 
    } 
} 

你會發現,這個類實現自己的類型的接口。該接口只定義了一個名爲ToObject方法,它用於將數據錶轉換爲一類特殊類型的:

public interface IFacetsObject<T> 
{ 
    IEnumerable<T> ToObject(DataTable obj); 
} 

現在,這裏是我用來執行查詢的方法:

public IEnumerable<T> ExecuteQuery<T>(string sql, IFacetsObject<T> obj) where T : new() 
{ 
    using (var conn = new AseConnection(_conn)) 
    { 
     conn.Open(); 
     var cmd = new AseCommand(sql, conn); 

     var dt = new DataTable(); 
     var da = new AseDataAdapter(sql, conn); 
     da.Fill(dt);     

     return obj.ToObject(dt); //this is the interface method 
    } 
} 

所以主要問題是: 如何才能知道T應該實現IFacetsObject<T>?這樣我就不必通過IFacetsObject<T>作爲參數。理想情況下,我可以改變返回行是這樣的:

return T.ToObject(dt); 

,並調用它是這樣的:

var result = ExecuteQuery<CMCGRGRGROUP>(sql).Take(5); 

,而不是像這樣:

var result = ExecuteQuery<CMCGRGRGROUP>(sql, new CMCGRGRGROUP()).Take(5); 

我承認我對泛型還不是非常熟悉,所以在實現中可能有些東西是不正確的。

+17

我看到你使用orkish變量命名約定 – Jonesopolis

+0

是的,它們很糟糕 - 不幸的是沒有命名數據庫表只是爲了保持名稱一致。 – Goose

+1

您無法從旁邊的界面繼承。(接口是_implemented_,行爲/實現是_inherited_) – sehe

回答

3

您可以在executeQuery方法添加約束。你已經有一個:要求T是新的。你會聲明它:

public IEnumerable<T> ExecuteQuery<T>(string sql, IFacetsObject<T> obj) 
    where T : IFacetsObject<T>, new() 
{ 
    using (var conn = new AseConnection(_conn)) 
    { 
     conn.Open(); 
     var cmd = new AseCommand(sql, conn); 

     var dt = new DataTable(); 
     var da = new AseDataAdapter(sql, conn); 
     da.Fill(dt);     

     return obj.ToObject(dt); //this is the interface method 
    } 
} 

所以它現在知道T是一個IFacetsObject<T>。你現在可以這樣做:

public IEnumerable<T> ExecuteQuery<T>(string sql) 
    where T : IFacetsObject<T>, new() 
{ 
    using (var conn = new AseConnection(_conn)) 
    { 
     conn.Open(); 
     var cmd = new AseCommand(sql, conn); 

     var dt = new DataTable(); 
     var da = new AseDataAdapter(sql, conn); 
     da.Fill(dt);     

     return new T().ToObject(dt); //this is the interface method 
    } 
} 

哪個國際海事組織仍然是非常醜陋的。

編輯迴應:

請注意,你不能叫T.ToObject - 一個接口不能定義靜態方法。解決方法是使用new來創建T的新實例並調用實例方法。

+0

它可能很醜,但我認爲這正是我所尋找的。非常感謝! – Goose

0

您需要在您的界面上使用通用約束。聲明這樣的:

public interface IFacetsObject<T> where T : IFacetsObject<T> 
{ 
    IEnumerable<T> ToObject(DataTable obj); 
} 

爲了得到這個工作,你也必須改變你這樣的聲明:

public IEnumerable<T> ExecuteQuery<T>(string sql, IFacetsObject<T> obj) 
    where T : IFacetsObject<T>, new() 
+0

問題是詢問我認爲的通用方法,而不是如何限制界面 – Wolfwyrd