Assume I have a class library project name Utilities.dll as follows:
public static class Utilities
{
public static T Min<T>(T[] data) where T : IComparable<T>
{
T min = data[0];
foreach (T x in data)
{
if (x.CompareTo(min) < 0)
min = x;
}
return min;
}
}
Then I create a new console app project Tester.exe referencing Utilities.dll as follows
class Program
{
static void Main(string[] args)
{
int[] data = { 3, 2, 4, 5, 1, 0, -1, 10 };
Console.WriteLine(Utilities.Min<int>(data));
}
}
I want to know how the compiler does its job behind the scene. Can anybody know the rough idea about it?
Note that: Assume I have no access to the source code of Utilities.dll when using it on Tester.exe project. Only Utilities.dll is provided.
In .NET (and unlike things like C++), it is the runtime that provides generics. The IL is structured to retain all the generic information (contrasting to Java, which uses type erasure).
In fact, you can create a new
Typeon the fly (viaTypeBuilder), and use reflecton:OT, but re your specific example, I actually recommend a change:
This will work even if
xis null, and supports “lifted” comparisons (againstNullable<T>). You can also then remove the generic constraint.But if we look at your original function, the IL is:
You can see the
T(for generics) is there, in full. The JIT (in most CLI implementations, not all) is responsible for figuring out what is necessary; typically all reference-type implementations share an implementation (since all references look the same under the hood), but each value-type implementation gets a separate JIT (as they have different memory layouts).