Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method overloads which differ only by generic constraint

Tags:

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

like image 520
Steffen Avatar asked Jul 08 '09 11:07

Steffen


People also ask

Can generic methods be overloaded?

A generic method can also be overloaded by nongeneric methods. When the compiler encounters a method call, it searches for the method declaration that best matches the method name and the argument types specified in the call—an error occurs if two or more overloaded methods both could be considered best ...

What are generic type constraints?

C# allows you to use constraints to restrict client code to specify certain types while instantiating generic types. It will give a compile-time error if you try to instantiate a generic type using a type that is not allowed by the specified constraints.

What does the generic constraint of type interface do?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.

Can a generic class have multiple constraints?

There can be more than one constraint associated with a type parameter. When this is the case, use a comma-separated list of constraints. In this list, the first constraint must be class or struct or the base class.


2 Answers

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.

like image 81
Marc Gravell Avatar answered Oct 25 '22 23:10

Marc Gravell


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) 
like image 44
Stefan Steinegger Avatar answered Oct 26 '22 00:10

Stefan Steinegger