C# for C++ Devs: Generics vs Templates for Primitive Types
I was trying to write some type-generic (almost) code in C# using a pattern that I commonly use in C++. A very simple version of what I was trying to do looks something like:
class B
{};template<typename T>
int convert(T value)
{
return (int)value;
}
int main(int argc, char* argv[])
{
convert(3.5f);
convert(11.5);
// The line below would fail with "error C2440: 'type cast' : cannot convert from 'B' to 'int'"
//convert(B());
return 0;
}
In C++ this compiles and runs just fine, as long as you don't uncomment the convert function for the class. For templates, code is only generated when needed at compile time and as long as the substituted code supports the required functions (or in this case cast), everything is just fine.
The equivalent C# program using generics looks like this:
class Program
{
static int convert<T>(T value)
{
return (int)value;
}
static void Main(string[] args)
{
convert(11.5);
}
}
Unfortunately it doesn't compile. I get an error: Cannot convert type 'T' to 'int'
This is due to the way generics are handled in C#. Instead of having code generated for different types at compile time, generics are resolved to the particular type at runtime (JIT actually). This means that the convert function shown above must support all types at compile time. This is not the case, since generic objects cannot always be converted to integers.
It is possible to use constraints if you are not using a primitive type, but there doesn't seem to be a nice way to support 'generic across primitive types' in C#. Am I missing something?
Comments
- Anonymous
July 03, 2007
I'm not a C++ user so I may be missing something, but your simple example can be done as follows: static int convert(IConvertible value) { return value.ToInt32(null); }IConvertible is implemented by all the primitive types.There's a boxing operation when calling that method (except when it's inlined by the JIT?), the following removes that: static int convert2<T>(T value) where T: IConvertible { return value.ToInt32(null); }Alan - Anonymous
July 03, 2007
You're right and it does solve my problem. I was still thinking like a C++ dev where primitive types are not classes themselves.I did a little extra reading (http://msdn2.microsoft.com/en-us/library/s1ax56ch(VS.80).aspx) and all the primitive (or simple) types are merely aliases for classes in the System namespace. For example, int is an alias for System.Int32. That class implements the IConvertible interface so I can use the constraint-based convert you list above.Thanks for the suggestion. - Anonymous
February 04, 2008
This error is due to the compile-time check of convertibility. However, this check can be circumvented so that only run-time checking takes place by first converting your type to "object". So, return (int)(object)value; would have worked just as well.