簡體   English   中英

T實現接口的通用方法<T>

[英]Generic method where T implements Interface<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);

我承認我還不太熟悉泛型,因此實現中可能存在某些不正確的地方。

您可以在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
    }
}

哪個IMO仍然很丑陋。

編輯回應:

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

您需要對接口進行一般約束。 像這樣聲明:

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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM