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).
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 ...
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.
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.
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.
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With