Consider this code snippet showing generics and overloaded functions:
using System;
namespace Test_Project
{
public interface Interface
{
void f();
}
public class U : Interface
{
public void f() {}
}
public class Class<T> where T: Interface
{
public static void OverloadedFunction(T a)
{
Console.WriteLine("T");
a.f();
}
public static void OverloadedFunction(U a)
{
Console.WriteLine("U");
a.f();
}
}
class Program
{
public static void Invoke(U instance)
{
Class<U>.OverloadedFunction(instance);
}
static void Main(string[] args)
{
Invoke(new U());
}
}
}
I would say that it does not compile, since I have two suitable methods for OverloadedFunction. However, he does and prints "U".
In the generated IL, I see that:
.method public hidebysig static
void Invoke (
class Test_Project.U 'instance'
) cil managed
{
// Method begins at RVA 0x2085
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call void class Test_Project.Class`1<class Test_Project.U>::OverloadedFunction(class Test_Project.U)
IL_0006: ret
} // end of method Program::Invoke
means that the C # compiler allowed the call to OverloadedFunction to a call instead of a callvirt, which would require a "common" function. I can guess that the "U" method is the best candidate from a compiler perspective, but I can’t explain exactly why ...
I would really like to understand what happened here, and I have no idea.
But it becomes even stranger if you consider this modified version of the fragment, where another level of indirection is introduced:
using System;
namespace Test_Project
{
public interface Interface
{
void f();
}
public class U : Interface
{
public void f() {}
}
public class V : U { }
public class Class<T> where T: Interface
{
public static void OverloadedFunction(T a)
{
Console.WriteLine("T");
a.f();
}
public static void OverloadedFunction(U a)
{
Console.WriteLine("U");
a.f();
}
}
class Program
{
public static void Invoke(V instance)
{
Class<V>.OverloadedFunction(instance);
}
static void Main(string[] args)
{
Invoke(new V());
}
}
}
, 'U', 'V' 'U' . "T", MSIL:
.method public hidebysig static
void Invoke (
class Test_Project.V 'instance'
) cil managed
{
// Method begins at RVA 0x208d
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call void class Test_Project.Class`1<class Test_Project.V>::OverloadedFunction(!0)
IL_0006: ret
} // end of method Program::Invoke
, #.
- , , ?