In C ++, every type that a program can create at runtime must be generated at compile time. While C ++ templates are similar to C # generators, their behavior is more akin to lookup macros. Since the compiler generates each class separately, which can arise as a result of general type substitutions, it can evaluate such things as overload resolution separately for each of them. C # generics do not work like that.
C # code compilation is divided into two phases. The first step is performed during assembly. The compiler that processes this phase takes the source code and converts it to the "Common Intermediate Language" form (the same CIL form is used for VB.NET, F #, etc. - this is where the name comes from). Each common class definition (for example, List<T> ) in the source code creates one class definition in the form of CIL. The compiler makes all decisions about which overload functions will be used before generating the CIL.
Later, when the program starts, the Common Language Runtime will not generate code for all classes that the program can use, but instead will delay code generation for each class until its first use. During this step, something like List<int> will generate different machine codes from List<string> or List<KeyValuePair<Dictionary<int,string>, Tuple<Cat,Dog>>> . The set of possible types that the program wants to use does not have to be limited. In C #, one could legitimately have a method that, taking into account the generic T parameter, would call a generic method with List<T> (and if the given List<T> passed List<List<T>> , and if given, then it would pass a List<List<List<T>>> etc.). A program is likely to die with an OutOfMemoryException or similar problem if things were nested too deep, but unlike C ++, the number of types that the program could generate does not have to be limited at compile time; only if the program tries to use too many different types will there be a problem.
The CLR is able to create some types of common substitutions when generating code, but it does not handle overload resolution (as already mentioned, it is processed at the stage of translating C # to CIL). While there may be some benefits to the CLR, such as overload resolution, it will also make the CLR much more complex. If a particularly complex problem with overloading takes a quarter of a second, it may not be a problem with compiling C # code, but stopping execution for a quarter of a second for such things would be undesirable.
source share