繁体   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