Generic method where T implements Interface<T>

c#, generics, inheritance, interface

Solution

You can add a constraint on your ExecuteQuery method. You already have one: requiring that T be newable. 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>`. 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.

EDIT Response:

Note that you cannot call T.ToObject - an interface cannot define a static method. The workaround is the use of new to create a new instance of T and call the instance method.

Problem

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: ``` 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>`? That way I don't have to pass `IFacetsObject<T>` as a parameter. 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.

Original source