Steffen
Steffen

Reputation: 13938

Method overloads which differ only by generic constraint

I've run into a bit of a problem, which I simply cannot find a good work-around to.

I want to have these 3 overloads:

public IList<T> GetList<T>(string query) where T: string
public IList<T> GetList<T>(string query) where T: SomeClass
public IList<T> GetList<T>(string query) where T: struct

Obviously the first constraint won't even compile alone, so that's my first issue. (I realise I could just make it IList but I want the same syntax for the three)

Anyway the reason for all this, is these methods are part of a wrapper around executing SQL queries against a database - I want to be able to return the result as a list of strings (in case someone selects a varchar column), a list of valuetypes (int, float, whatever) or a list of classes (these classes represent tables, and thus contains multiple columns)

I hope that part was somewhat understandable :-)

Anyway my big problem is obviously that I cannot make these overloads, since they use the same name and parameterlist.

Also I cannot merge them into the same method, since I need to call a method on SomeClass in that implementation, so unless I want to do some heavy typecasting, or worse, reflection - I need that constraint.

I realise that what I'm trying to do isn't possible, so what I'm searching for is a good approach, that'll mimic my intentions.

If some of this is a bit unclear, feel free to ask :-)

Edit:

Here's my current code for the "where T: SomeClass" version. I'm trying to add support for string/valuetypes to this current code, so maybe my initial approach is just plain wrong - any ideas are welcome basically :-)

public IList<TValue> GetList<TValue>(string query) where TValue : DbTable, new()
{
    DataSet dataSet = GetDataSet(query);
    IList<TValue> result = new List<TValue>();

    if (dataSet.Tables.Count > 0)
    {
        foreach (DataRow row in dataSet.Tables[0].Rows)
        {
            TValue col = new TValue();
            col.Fill(row);
            result.Add(col);
        }
    }

    return result;
}

As you can see I need the exact type of DbTable in order to new the proper constructor. Fill is an abstract method of DbTable (which is an abstract class).

Upvotes: 27

Views: 4893

Answers (2)

Stefan Steinegger
Stefan Steinegger

Reputation: 64628

what about this?

public IList<T> GetList<T>(string query) where T : new()
{
  // whatever you need to distinguish, this is a guess:
  if (typeof(T).IsPrimitiveValue)
  {
    GetPrimitiveList<T>(query);
  }
  else if (typeof(T) == typeof(string))
  {
    GetStringList<T>(query);
  }
  else
  {
    GetEntityList<T>(query);
  }

}

private IList<T> GetStringList<T>(string query)

private IList<T> GetPrimitiveList<T>(string query)

private IList<T> GetEntityList<T>(string query)

Upvotes: 3

Marc Gravell
Marc Gravell

Reputation: 1062715

As you note; there aren't any good options for this. You might consider different names (rather than overloads) - GetStringList etc.

However, I wonder whether it would be simpler to drop the constraint. A single type-check with "as" isn't exactly "heavy" type-casting, and it might save a lot of pain.

Upvotes: 14

Related Questions