Let's assume we have:
public static class MyClass<T> where T : new()
{
static MyClass()
{
_instance = new T();
}
private static T _instance;
public static T Get() => _instance;
public static void Set(T instance) => _instance = instance;
}
What happens when we then call:
Foo foo = MyClass<Foo>.Get();
Bar bar = MyClass<Bar>.Get();
Or more specifically, how does that gets compiled..
- Does this create some sort of
Dictionary<Type, [MyClass's implementation with Type as the generic arg]>
, such that every call to a member onMyClass<T>
would constitute a dictionary lookup? - or, does it perform a compile-time analysis to find all possible generic args to
MyClass<T>
, and create distinct types accordingly, each mapped to its corresponding caller? I imagine this latter case would need support by the JIT to handle reflection scenarios. - or, does it work in an entirely different way than those mentioned above?
I'd appreciate if someone could explain this, or refer me to a useful resource.
UPDATE:
I have seen the following questions, along with the answers and references mentioned there.
- How C# generic works? [duplicate]
- How are generic methods stored?
- Generics in the Run Time (C# Programming Guide)
These resources do offer the valuable insight that only one type is compiled while multiple types could be created by the runtime. Although this insight does add to the context of the question, the question is more concerned about the dynamics of accessing members defined on generic types (for which the runtime has already created specialized types).
In order to not get distracted, I'm mostly interested in the performance perspective for the purpose of micro-optimization.
If I'm to rephrase, let's assume we have MyClass<T>
as mentioned in the OC, and then we add:
public static class MyFoo
{
static MyFoo()
{
_instance = new Foo();
}
private static Foo _instance;
public static Foo Get() => _instance;
public static void Set(Foo instance) => _instance = instance;
}
And then add a thousand more of these MyFoo
for different types. Does each of the following lines has exactly the same complexity/performance (when called for a thousand types)?
Foo foo1 = MyClass<Foo>.Get();
Foo foo2 = MyFoo.Get();