I can't find an answer to this anywhere and all my code hacks fail to compile. The shoprt story is like this.
I can write a generic method that looks loosely like (off the top of my head):
private T First<T>(T a, T b) { return a; }
(sure this is a meaningless example but hey, I'm exploriung a point not an application).
Now let's say I want to constrain the type T, this is fine (and a much cited example of sorts):
private T First<T>(T a, T b) where T : IComparable { return a; }
Now the fun begins. I want to constrain T to a generic interface not a specific one. Try this:
private T First<T>(T a, T b) where T : IComparable<T2> { return a; }
and whammo, compile time error:
Error 1 The type or namespace name 'T2' could not be found (are you missing a using directive or an assembly reference )
In summary, if you try compiling this:
private T First1<T>(T a, T b) { return a; }private T First2<T>(T a, T b) where T : IComparable { return a; }
private T First3<T>(T a, T b) where T : IComparable<T2> { return a; }
First3 generates the error.
To be honest what I'm trying to do is more like:
private T First4<T>(T a, T b) where T : IDictionary<TK, TV> { return a; }
constraining a generic method to accept only types implementing the IDictionary interface. But I don't want a specific IDictionary I need to support any (i.e. the generic) IDictionary. It seems that unlike the IComparable interface the IDictionary iterface requires the type arguments (isn't implemented as a generic generic). In short, this analogy of First2 is not possible:
private T First5<T>(T a, T b) where T : IDictionary { return a; }
This generates the compile time error:
Error 1 Using the generic type 'System.Collections.Generic.IDictionary<TKey,TValue>' requires '2' type arguments
It looks, on the face of it, that a generic generic like this isn't supported by C# (or I'm failing to find the syntax that does). Am I right

Generic generics ... can Generic methods be constrained to accept generic types?
barisrael
You are correct. You'd have to do something more like:
private T First6<T,U>(T a, Tb) where T: IComparable<U>, U:somethingifyouwant {return a;}
Think what would happen if it could compile - When you compile code calling First3 (in your example), it must be able to resolve T2 to see if T satisfied the constraint (of being an IComparable<T2>). However it can not determine if T is also a IComparable<T2>, since T2 is not specified.
Let's say that First3 were defined as
private T First3(T a, T b) where T: IComparable<T2>
{ a.CompareTo(b);}
Since a.CompareTo takes a parameter of T2, how would the compiler ensure that b can be cast to a T2 since it has no idea what a T2 is
BillGo
You may not be fussed about what T2 is, but of course the compiler doesn't know that. All it knows is that T2 must be a type of some sort, and it expects to be able to find a declaration for T2 somewhere. Hence the need to put it in the list of type variables:
T1 First<T1, T2>(T1 a, T1 b) where T1 : IComparable<T2>
Of course, as James pointed out, there are probably better ways of declaring this method. If all you're trying to ensure is that "a" and "b" implement the IComparable<T> interface, the following may make more sense:
IComparable<T> First<T>(IComparable<T> a, IComparable<T> b)
Does this answer your caveat
-Tom Meschter
Software Dev, Visual C# IDE
Furqan Farooqui
The problem with that is how do you call it IF we were to write :
Dictionary<int, string> c=null, d=null;
IDictionary<int, string> e = First4(c, d);
IDictionary<int, string> e = First4<Dictionary<int, string>, int, string>(c, d);
In theory, we should be able to write it as :
// Note order of type parameters
private T First4<K, V, T>(T a, T b) where T : IDictionary<K, V> {....}
// :
// : IDictionary<int, string> e = First4<int, string>(c, d);
But apparently C# insists on all or nothing when it comes to type paramters (even if it can infer the missing ones). (Similar code compiles in C++)
So, in the end, what we really want is:
private IDictionary<TK, TV> First5<TK, TV>(IDictionary<TK, TV> a, IDictionary<TK, TV> b) { return a; }
// :
// :
Dictionary<int, string> c=null, d=null;
IDictionary<int, string> e = First5(c, d);
breceivemail
Fantastic! Thanks guys. I can't believe how quickly you've got m,e rolling again. I could have spent the whole intervening time and then some I imagine googling around and searching help for this answer. None of the worked examples or even treatises I stumbled across and scanned touched on this theme so lucidly as to aid my comprehension.
Thanks again!
(Caveat: I am not 100% clear why at compile time it needs to resolve T2 int he cited examples. The whole point is, I'm not fussed what T2 is, as long as T meets the IComparable interface. In case o IcomparableI can just leave the type arguments off, but not with IDictionary which is what frustrates. But the solutions provided do work and don't cause me any problem they get me rolling!).
Babax
The problem with:
private T First3<T>(T a, T b) where T : IComparable<T2>
{
return a;
}
is that you haven't declared "T2" anywhere. The only type variable that "First3" knows about is "T". What you would need to do instead is this:
private T1 First3<T1, T2>(T1 a, T1 b) where T1 : IComparable<T2>
{
return a;
}
So for "First4" you need to declare it like so:
private T First4<T, K, V>(T a, T b) where T : IDictionary<K, V>
{
return a;
}
Hope this is what you're looking for.
-Tom Meschter
Software Dev, Visual C# IDE