Krumelur
Krumelur

Reputation: 33048

C# extension methods not working as expected - see example

I'm wondering about the behavior of extension methods in C#. Please see the examples below:

static string ExtendedToString( this object oObj )
{
    return "Object";
}

static string ExtendedToString( this Array oArray )
{
    return "Array";
}

// Example 1: int array - working as expected.
int[] o = new int[] { 1, 2, 3 };
o.ExtendedToString( ); // returns "Array"

// Example 2: array as object - did not expect the result.
object o = new int[] { 1, 2, 3 };
o.ExtendedToString( ); // returns "Object"

Why is (in the last case) the object's extension method called and not the one for int[]?

Upvotes: 1

Views: 581

Answers (4)

CodesInChaos
CodesInChaos

Reputation: 108790

Thomas Levesque already has a perfect explanation of why your code doesn't work, so I won't repeat that. The work around is testing at runtime with is or as:

static string ExtendedToString( this object oObj )
{
    if(oObj is Array)
        return "Array";
    else
        return "Object";
}

Generally type testing in such a way is a bit of an anti-pattern and you should prefer virtual methods where possible. But in this case it's probably still the best solution since you can't change the Array/Object classes.

If there are many classes which need special treatment you could consider a Type -> Func<object,string> Dictionary.

Upvotes: 0

archil
archil

Reputation: 39491

Because of static typing. Extension methods are rewrited by compiler as if you called them by regular syntax. At the compile time, second object o has the type of Object, so object's extension method is called

Upvotes: 1

Thomas Levesque
Thomas Levesque

Reputation: 292355

Overload resolution is performed at compile time. The compiler sees that o is declared as object, so it calls the overload that takes an object. The fact that o actually contains an array at runtime is irrelevant, because the compiler doesn't know it.

That's actually not specific to extension methods, you would get the same result by calling it as a normal static method (ExtensionsClass.ExtendedToString(o))

Upvotes: 9

mbx
mbx

Reputation: 6526

You declared o as object:

object o = new int[] { 1, 2, 3 };

thats why:

o.ExtendedToString( ); // returns "Object"

but you can

int[] obj = o as int[];
obj.ExtendedToString( ); // returns "Array"

as the resolution is depending on the (static) type

Upvotes: 1

Related Questions