Diese Frage hat mich gefragt, wo die konkrete Implementierung einer generischen Methode tatsächlich zustande kommt. Ich habe Google ausprobiert, finde aber nicht die richtige Suche.
Wenn wir dieses einfache Beispiel nehmen:
class Program
{
public static T GetDefault<T>()
{
return default(T);
}
static void Main(string[] args)
{
int i = GetDefault<int>();
double d = GetDefault<double>();
string s = GetDefault<string>();
}
}
In meinem Kopf habe ich immer angenommen, dass es irgendwann zu einer Implementierung mit den 3 notwendigen konkreten Implementierungen führt, so dass wir bei naivem Pseudo-Mangling diese logische konkrete Implementierung haben würden, bei der die verwendeten spezifischen Typen zu den richtigen Stapelzuordnungen usw. führen .
class Program
{
static void Main(string[] args)
{
int i = GetDefaultSystemInt32();
double d = GetDefaultSystemFloat64();
string s = GetDefaultSystemString();
}
static int GetDefaultSystemInt32()
{
int i = 0;
return i;
}
static double GetDefaultSystemFloat64()
{
double d = 0.0;
return d;
}
static string GetDefaultSystemString()
{
string s = null;
return s;
}
}
Betrachtet man die IL für das generische Programm, so wird es immer noch in generischen Typen ausgedrückt:
.method public hidebysig static !!T GetDefault<T>() cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init ([0] !!T CS$1$0000,
[1] !!T CS$0$0001)
IL_0000: nop
IL_0001: ldloca.s CS$0$0001
IL_0003: initobj !!T
IL_0009: ldloc.1
IL_000a: stloc.0
IL_000b: br.s IL_000d
IL_000d: ldloc.0
IL_000e: ret
} // end of method Program::GetDefault
Wie und an welchem Punkt wird entschieden, dass ein int, dann ein double und dann eine Zeichenfolge auf dem Stapel zugewiesen und an den Aufrufer zurückgegeben werden müssen? Ist dies eine Operation des JIT-Prozesses? Betrachte ich das im völlig falschen Licht?