简体   繁体   English

T实现接口的通用方法<T>

[英]Generic method where T implements Interface<T>

I'm trying to create a generic data retrieval process. 我正在尝试创建一个通用的数据检索过程。 What I have currently works, but there is a part of it that doesn't seem right and I'm hoping there is a better way to accomplish it. 我目前可以使用的软件,但是其中一部分似乎并不正确,我希望有一种更好的方法来完成它。

So the idea is that I have classes for each table in the database, here is an example of a class: 因此,想法是我为数据库中的每个表都有类,这是一个类的示例:

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

You'll notice that the class implements an interface of its own type. 您会注意到该类实现了自己类型的接口。 The interface simply defines a method called ToObject , which is used to convert a datatable to a class of that particular type: 该接口仅定义了一个称为ToObject的方法,该方法用于将数据表转换为该特定类型的类:

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

Now, here is the method that I am using to execute a query: 现在,这是我用来执行查询的方法:

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
    }
}

So the main question is: How can the generic method know that T should implement IFacetsObject<T> ? 因此,主要问题是:通用方法如何知道T应该实现IFacetsObject<T> That way I don't have to pass IFacetsObject<T> as a parameter. 这样,我不必传递IFacetsObject<T>作为参数。 Ideally, I could change the return line to be something like this: 理想情况下,我可以将返回线更改为以下形式:

return T.ToObject(dt);

And call it like this: 并这样称呼它:

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

Instead of like this: 而不是像这样:

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

I'll admit that I'm not terribly familiar with generics yet so there may be something within the implementation that isn't right. 我承认我还不太熟悉泛型,因此实现中可能存在某些不正确的地方。

You can add a constraint on your ExecuteQuery method. 您可以在ExecuteQuery方法上添加约束。 You already have one: requiring that T be newable. 您已经有一个:要求T是可更新的。 You'd declare it like: 您可以这样声明:

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
    }
}

So it now knows T is an IFacetsObject<T> . 因此,现在知道T是IFacetsObject<T> You could now do: 您现在可以执行以下操作:

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
    }
}

Which IMO is still pretty ugly. 哪个IMO仍然很丑陋。

EDIT Response: 编辑回应:

Note that you cannot call T.ToObject - an interface cannot define a static method. 请注意,您不能调用T.ToObject-接口不能定义静态方法。 The workaround is the use of new to create a new instance of T and call the instance method. 解决方法是使用new来创建T的新实例并调用instance方法。

You need a generic constraint on your interface. 您需要对接口进行一般约束。 Declare it like this: 像这样声明:

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

In order to get this to work, you also have to change your declaration like this: 为了使它起作用,您还必须像这样更改声明:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通用方法,其中 T 是实现接口的列表 - Generic Method where T is List that implements interface 检查对象是否使用通用接口实现接口 <T> 泛型类型是T的子代 - Checking if an object implements an interface with a generic <T> where the generic type is a child of T 除非T实现接口I,否则需要通用方法返回类型T,在这种情况下,返回I - Need generic method to return type T unless T implements interface I, in which case return I 为什么我不能将一个项目转换为泛型类型——其中泛型类型是一个接口,并且在检查该项目是否实现了所述接口之后? - Why can't I cast an item to a generic type — where the generic type is an interface, and after checking that the item implements said interface? BindingList <T>其中T是实现其他接口的接口 - BindingList<T> where T is interface that implements other interface T型通用接口,其中 - Generic Interface with Type T and where 在实现通用接口方法的方法中专门化类型 - Specialize type in method that implements a generic interface method 上载到接口 <Foo> 当类实现通用接口时 <T> 类型约束为T = Foo? - Upcasting to an Interface<Foo> when a class implements generic Interface<T> with type constraint T=Foo? 为什么是Generic <T> 具有“where T:class”约束的方法接受接口 - Why does a Generic<T> method with a “where T : class” constraint accept an interface 我可以将一个实现接口的通用 T 数组转换为这个特定的接口数组吗? - Can I cast a generic array of T that implements an interface, to this specific interface array?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM