views:

362

answers:

6

The following code sample prints:

T
T[]
T[]

While first two lines are as expected, why compiler selected param array for a regular array?

public class A
{
    public void Print<T>(T t)
    {
        Console.WriteLine("T");
    }

    public void Print<T>(params T[] t)
    {
        Console.WriteLine("T[]");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        a.Print("string");
        a.Print("string","string");
        a.Print(new string[] {"a","b"});
    }
}
+10  A: 

Under the hood

a.Print("string","string");

is just syntactic sugar for

a.Print(new string[]{"string","string"});

EDIT: Like I said, the params keyword only automagically creates the array for you, you tell the compiler: either accept an array of T directly or use the X input params to construct that array.

arul
Re-read the question.
strager
@strager: You should read the question. arul is right.
Samuel
Okay, maybe I'm totally misunderstanding something here. Can you elaborate your answer a bit?
strager
MSIL doesn't have a concept of the params keyword for parameters. So the C# compiler sees the params on the parameter and when is being called actually changes the arguments to be an array.
Samuel
Ah, I see. Your example didn't make sense at first, because you're looking at the second and not the last method call. Now I get it. Thanks. =]
strager
I think the question is why does the compiler not choose a.Print<string[]> the first method, what rule says the params method is a better fit.
JoshBerke
Because when making the actual params method call, the variable-length parameter set will be translated to T[], and so it fits the T[] version more. Remember, arrays are its own Array class, while for the first version, string is a class, not Array class though.
TimeSpace Traveller
A: 

Params allows you to pass multiple objects of the same type. it is a shortcut way of passing array

Mitchel Sellers
As others write, there's no such thing as a params array, nor is there any 'mapping to a params array'. It's just an array and params keyword allows for a writing a more compact syntax.
Robert Paulson
Sorry for the incorrect word...
Mitchel Sellers
A: 

I think this actually has more to do with type inference than with the params keyword. The inference engine assumes on the third line that the type of T is string[] and therefore passes it to the first method.

try Console.WriteLine(typeof(T)) if you don't believe me

George Mauer
The first method prints just 'T', so you are wrong.
Prankster
nope, you're not getting what I'm saying. The first the inference engine maps T to type string, the 3rd it maps T to type string[]. Just replace your console outputs with Console.WriteLine(typeof(T)); and you'll see
George Mauer
@George, You're incorrect: T will be string in all three cases.
LukeH
The second and third method calls are identical to the computer. Syntactic sugar.
Mike Christiansen
A: 

when having the params keyword, the compiler will do a little bit of translation for the formal function declaration, as well as the actual function call.

Formal function declaration:

Under the hood, the IL will be translated to essentially the same as

public void Print<T>(T[] array);

Except, when compiling, the actual function call will be checked for syntax translation. Meaning,

a.Print("string1", "string2");

Becomes the same IL code as

a.Print(new string[]{"string1", "string2"});

That is why line 2 and 3 are the same output, because under the hood, they got translated to the exact same IL.

Question about why line 3 is not print "T" is because, .NET compiler will always try to find the best overloaded match, and so both line 2 and 3 called to the T[] version instead of the plain T.

TimeSpace Traveller
A: 

Exactly as arul said. If you open up the project in reflector, you'll see the following:

a.Print<string>(new string[] { "string", "string" });
aquinas
+5  A: 

It addition to what others have said, the params keyword also causes a ParamArrayAttribute to the generated for array parameter. So, this...

public void Print<T>(params T[] t) { }

Is generated by the compiler as...

public void Print<T>([ParamArray] T[] t); { }

It is that attribute which indicates to the compiler and the IDE that the method can be called using simpler syntax...

a.Print("string", "string");

rather than...

a.Print(new string[] { "string", "string" });
Dustin Campbell