Originally posted by: Markbnj
Originally posted by: Chris
You're sort of abusing generics. The generic types should be used for single-types, or type hierarchies, not disparate types (int, DateTime).
You're better off just doing something less sexy but more sensible like:
I think the answer is somewhat different here. In the OP's example the method signature...
public static string Foo<T>(List<T> items) where T : int, DateTime { //... }
... produces the error...
'System.DateTime' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
... on compilation with the snippet compiler, because int and DateTime are both structures. Structures in C# are implicitly sealed, and sealed types cannot be used in a constraint on a generic method.
If you remove the constraint clause you get the error the OP referenced. I think what is going on here is different from what you suggested. The problem I see is that in the OP's implementation of Foo<T>() he expects the compiler to be able to resolve the call to SpecialPrint(Item) at compile time, however the compiler does not yet know what the actual type of T is.
If you include a call of Foo<T>() for, say, int, then you still get the same error. Why? The compiler should now know that Foo<T>() is being called for int, and should be able to determine that the call to SpecialPrint(Item) is for a context where typeof(Item) == int. But C# generics don't work like C++ templates, in that they are not fully instantiated at compile time. Instead the compiler produces IL with place-holders, and then the JIT translator evaluates the parameters supplied at runtime, and creates the appropriate machine code. If the supplied parameter is a value type, the machine code generated uses native types. If the param is a reference type, the machine code uses Object and generates runtime type checking.
So the key point is that the type of T is not known at compile time, so the call to SpecialPrint(Item) cannot be resolved. The only way around this is to do the checking yourself at runtime, as far as I know. See...
http://msdn2.microsoft.com/en-us/librar...564(vs.80).aspx
Edit: should also mention that Chris' advice about not mixing types in a collection (other than a singly-rooted hierarchy) is solid. Also worth stating that C# generics were, as he said, added primarily to support type-safe collections. You're operating at the edges by trying to use them as a mechanism to get generic dispatching at runtime.