tags:

views:

132

answers:

3

Say I have the following methods:

public static void MyCoolMethod(params object[] allObjects)
{
}

public static void MyCoolMethod(object oneAlone, params object[] restOfTheObjects)
{
}

If I do this:

MyCoolMethod("Hi", "test");

which one gets called and why?

+5  A: 

The second one, the compiler will first try to resolve against explicitly declared parameters before falling back on the params collection.

kekekela
+10  A: 

It's easy to test - the second method gets called.

As to why - the C# language specification has some pretty detailed rules about how ambiguous function declarations get resolved. There are lots of questions on SO surrounding interfaces, inheritance and overloads with some specific examples of why different overloads get called, but to answer this specific instance:

C# Specification - Overload Resolution

7.5.3.2 Better function member

For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list.

Parameter lists for each of the candidate function members are constructed in the following way:

  • The expanded form is used if the function member was applicable only in the expanded form.

  • Optional parameters with no corresponding arguments are removed from the parameter list

  • The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

And further on...

In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent > (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.

  • If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.

  • Otherwise, if MP is applicable in its normal form and MQ has a params array and is applicable only in its expanded form, then MP is better than MQ.

  • Otherwise, if MP has more declared parameters than MQ, then MP is better than MQ. This can occur if both methods have params arrays and are applicable only in their expanded forms.

The bolded tie-breaking rule seems to be what is applying in this case. The specification goes into detail about how the params arrays are treated in normal and expanded forms, but ultimately the rule of thumb is that the most specific overload will be called in terms of number and type of parameters.

womp
Quote From Eric Lippert: *When given a call that is applicable in both forms, the compiler always chooses the normal form over the expanded form.*
ChaosPandion
+1 for anything from Eric.
womp
So is there any way to call the first method?
Vaccano
Absolutely. Try: `MyCoolMethod(new object[] {"HI", "test"});`
womp
@womp: I'm not sure if your quote from the spec actually explains how these two methods are disambiguated. More recent versions of the spec provide extra information in the "Better function member" section.
LukeH
LukeH
Section 14.4.2.2 of the ECMA-334 C# spec: "Otherwise, if the numbers of parameters *K* in *MP* and *L* in *MQ* are different, then the method with more parameters is better. Note that this can only occur if both methods have `params` arrays and are only applicable in their expanded forms." http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf
LukeH
@LukeH - thanks for pointing this out. That does seem more directly applicable, and Eric's comments in ChaosPandion's question are along the same lines. It looks like 7.4.2.2 in the older reference was updated to specifically include more specific `params` information. I'll edit the post to use the more up to date spec. Ultimately it's the same "most specific" principle that's being applied.
womp
Great answer and comments. Thanks!
Vaccano
A: 

This overload is tricky...

MyCoolMethod("Hi", "test") obviously calls the 2nd overload, but

MyCoolMethod("Hi"); also calls the 2nd overload. I tested this.

Maybe since both of the inputs are objects, the compiler assume anything passed in will be an array of objects and completely ignores the 1st overload.

It probably has to do with the Better function member resolution mentioned by womp http://msdn.microsoft.com/en-us/library/aa691338(v=VS.71).aspx

Ed B