tags:

views:

149

answers:

2

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).

+5  A: 

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.

Marc Gravell
Yes different names is simple, however I want to make it almost as if it was just one and the same method, that acceps these constraints.I could make a GetList<T> without constraint, and then throw an exception if the type is wrong - however in the case of SomeClass, it's actually classes which inherit SomeClass, and I need the exact type, since I new() them.Hang on a sec, and I'll post my existing GetList<T> where T: SomeClass code.
Steffen
In that case it can get messy with `MakeGenericMethod` etc; not a good option.
Marc Gravell
Exactly - and you're right that a simple type-check for the strings and valuetypes aren't troublesomel.It's getting the child types off of DbTable I'm worried about.
Steffen
I'll go with different names, as what I'm trying to do isn't really possible in a feasible way (reflection could do it, but I really don't want that)
Steffen
A: 

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)
Stefan Steinegger
Yes that'd almost work, the only problem being GetEntityList - as you can see from my code example, I need to be able to new() T, and call Fill on it - neither is possible without a constraint *or* reflection (which I'd rather not)The rest however would work just fine.
Steffen
You'll need a runtime check for the interfaces implementation ('as'). Reflection is not needed. Or - make the methods with specific names (GetEntityList) public and call it directly.
Stefan Steinegger
Stefan - I have at the very least a dozen implementations of DbTable (since I have a class per table in my database), so testing with as is not really feasible, besides the implementations are usually outside the scope of the library.As for calling it directly, I'm starting to believe that is in fact the only solution :-/
Steffen
You misunderstood: I mean testing with 'as' to the base type DbTable (I hope this is an abstract base type, even better it would be an interface). By the way, before spending too many days on a DAL library like this, take a look at NHibernate!
Stefan Steinegger
Stefan - my bad with the 'as' operator, and yes DbTable is an abstract base type.The issue is that I have to instantiate the proper implementation of DbTable.As for NHibernate I actually finished version 1 of this DAL library before learning about NHibernate, so I've got too many projects running on this library, to just give it up at all together :-) (Thanks for the tip though)
Steffen