c# - T 实现 Interface<T> 的通用方法

标签 c# generics inheritance interface

我正在尝试创建一个通用的数据检索过程。我目前所做的工作有效,但其中有一部分似乎不正确,我希望有更好的方法来完成它。

所以我的想法是为数据库中的每个表创建类,这是一个类的示例:

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

您会注意到该类实现了它自己类型的接口(interface)。该接口(interface)简单地定义了一个名为 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 - 接口(interface)不能定义静态方法。解决方法是使用 new 创建 T 的新实例并调用实例方法。

关于c# - T 实现 Interface<T> 的通用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22616560/

相关文章:

haskell - 了解如何构建 GHC.Generics Rep 并转换回值

c# - 我如何判断我的泛型类型是否支持某个接口(interface)并为函数来回转换到该接口(interface)?

c# - 在 C# 中,override 修饰符在派生类中对于基类的虚拟/抽象方法是强制性的

c# - 显示使用 ajax 更新的多个相关 ViewModel 的 MVC 页面

c# - 将具有递归的SQL查询转换为LINQ

c# - 如何删除级联底部的实体 -> EF中的非级联删除链?

generics - 为什么我的泛型函数没有为元组单态化?

Ruby 类继承 : How to preven a public method from beeing overwritten in the child classes

c++ - 继承自虚类并在构造时指定

c# - 使用 C# 代码检查默认邮件客户端