I wrote about a data structure we call the “runtime generic context” in my previous posts on sharing generic code. We use this data structure to store type information that shared generic code needs to access that is specific for each instantiation of the generic type.
It follows that shared generic code must have easy access to the runtime generic context – otherwise it couldn’t efficiently access that data. Non-static methods of generic classes access the runtime generic context through the vtable which they can get to via the implicit “this” argument. Static methods do not get this implicit argument, however, and need some other means of accessing the runtime generic context.
Our solution to this problem is to pass the runtime generic context as an additional argument to shared static methods. By doing this we create another problem: The pointer to the code of the method suddenly isn’t enough anymore to call the method. That becomes an issue when the method is to be used as a delegate, for example, where the caller does not and cannot know that the method needs an additional argument.
What we do in those cases is provide an additional piece of code that calls the method and also passes the correct runtime generic context. As such, this piece of code is specific to an instantiation of a generic type, i.e. it is not shared between instantiations (which is the whole point). Right now this piece of code is a wrapper but we will probably replace it by a piece of custom-generated machine code which will be much shorter and more efficient.
Side-note: Methods of generic value types can be handled in exactly the same way. Value type objects don’t have vtables so we have to pass the runtime generic context explicitly, just like for static methods.