Similar Extension methods are there any differences?

What are the differences between these two extension methods?

public static class Test
{
    public static int First<T>(this T obj)
    {
        return 2;
    }

    public static int Second(this object obj)
    {
        return 2;
    }
}
Jon Skeet
people
quotationmark

There are a few differences, yes. The first one won't box value types - but will end up JIT-compiling the method multiple times for different type arguments (once for all reference types, and once per value type).

So:

byte x1 = 10;
int y1 = x1.First(); // No boxing

byte x2 = 10;
int y2 = x2.Second(); // Boxes before the call

The IL generated is:

IL_0001:  ldc.i4.s   10
IL_0003:  stloc.0
IL_0004:  ldloc.0
IL_0005:  call       int32 Test::First<uint8>(!!0)
IL_000a:  stloc.1
IL_000b:  ldc.i4.s   10
IL_000d:  stloc.2
IL_000e:  ldloc.2
IL_000f:  box        [mscorlib]System.Byte
IL_0014:  call       int32 Test::Second(object)

Additionally, within your First extension method, you could get the compile-time type of T separately from the execution-time type of the object referred to by obj. So for example, changing the body of the methods:

public static class Test
{
    public static int First<T>(this T obj)
    {
        Console.WriteLine("Compile-time type: {0}", typeof(T));
        Console.WriteLine("Execution-time type: {0}", obj.GetType());
        return 2;
    }

    public static int Second(this object obj)
    {
        // No compile-time type to know about
        Console.WriteLine("Execution-time type: {0}", obj.GetType());
        return 2;
    }
}

Then:

Stream foo = new MemoryStream();
foo.First(); // Will print Stream, then MemoryStream
foo.Second(); // Only knows about MemoryStream

people

See more on this question at Stackoverflow