In C#, the concepts of generic types and methods is supported by the runtime itself. The C# compiler does not need to actually create a concrete version of a generic method.
The actual “concrete” generic method is created at runtime by the JIT, and does not exist in the IL. The first time a generic method is used with a type, the JIT will see if it’s been created, and if not, construct the appropriate method for that generic type.
This is one of the fundamental differences between generics and things like templates in C++. It’s also the main reason for many of the limitations with generics – since the compiler isn’t actually creating the runtime implementation for types, the interface restrictions are handled by compile time constraints, which make generics a bit more limiting than templates in C++ in terms of potential use cases. However, the fact that they are supported in the runtime itself allows creation of generic types and usage from libraries possible in ways that aren’t supported in C++ and other compile-time created template implementations.