{"id":3603,"date":"2013-08-06T07:00:00","date_gmt":"2013-08-06T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/08\/06\/the-mysterious-ways-of-the-params-keyword-in-c\/"},"modified":"2013-08-06T07:00:00","modified_gmt":"2013-08-06T07:00:00","slug":"the-mysterious-ways-of-the-params-keyword-in-c","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130806-00\/?p=3603","title":{"rendered":"The mysterious ways of the params keyword in C#"},"content":{"rendered":"<p>\nIf a parameter to a C# method is declared with the\n<code>params<\/code> keyword,\nthen it can match either itself or a comma-separated list of\num itselves(?).\nConsider:\n<\/p>\n<p><pre>\nclass Program {\n  static void Sample(params int[] ints) {\n   for (int i = 0; i &lt; ints.Length; i++) {\n    System.Console.WriteLine(&quot;{0}: {1}&quot;, i, ints[i]);\n   }\n   System.Console.WriteLine(&quot;-----&quot;);\n  }\n  public static void Main() {\n   Sample(new int[] { 1, 2, 3 });\n   Sample(9, 10);\n  }\n}\n<\/pre>\n<p>\nThis program prints\n<\/p>\n<pre>\n0: 1\n1: 2\n2: 3\n-----\n0: 9\n1: 10\n-----\n<\/pre>\n<p>\nThe first call to <code>Sample<\/code>\ndoes not take advantage of the <code>params<\/code> keyword\nand passes the array explicitly (formally known as\n<i>normal form<\/i>).\nThe second call, however, specifies the integers directly\nas if they were separate parameters.\nThe compiler generates a call to the function in what the language\nspecification calls <i>expanded form<\/i>.\n<\/p>\n<p>\nNormally, there is no conflict between these two styles of\ncalling a function with a <code>params<\/code> parameter\nbecause only one form actually makes sense.\n<\/p>\n<pre>\nSample(new int[] { 0 }); \/\/ normal form\nSample(0); \/\/ expanded form\n<\/pre>\n<p>\nThe first case must be called in normal form because you cannot\nconvert an <code>int[]<\/code> to an <code>int<\/code>;\nconversely, the second case must be called in expanded form because\nyou cannot convert an <code>int<\/code> to an <code>int[]<\/code>.\n<\/p>\n<p>\nThere is no real problem in choosing between the two cases\nbecause <code>T<\/code> and <code>T[]<\/code> are not implicitly\nconvertible to each other.\n<\/p>\n<p>\nOh wait.\n<\/p>\n<p>\nUnless <code>T<\/code> is <code>object<\/code>!\n<\/p>\n<pre>\nclass Program {\n  static void Sample(params object[] objects) {\n   for (int i = 0; i &lt; objects.Length; i++) {\n    System.Console.WriteLine(&quot;{0}: {1}&quot;, i, objects[i]);\n   }\n   System.Console.WriteLine(&quot;-----&quot;);\n  }\n  public static void Main() {\n   Sample(new object[] { &quot;hello&quot;, &quot;there&quot; });\n  }\n}\n<\/pre>\n<p>\nThere are two possible interpretations for that call to\n<code>Sample<\/code>:\n<\/p>\n<ul>\n<li>Normal form: This is a call to <code>Sample<\/code>\n    where the <code>objects<\/code> is an array of length&nbsp;2,\n    with elements <code>\"hello\"<\/code> and <code>\"there\"<\/code>.<\/p>\n<li>Expanded form: This is a call to <code>Sample<\/code>\n    where the <code>objects<\/code> is an array of length&nbsp;1,\n    whose sole element is the array\n   <code>new object[] { \"hello\", \"there\" }<\/code>.\n<\/ul>\n<p>\nWhich one will the compiler choose?\n<\/p>\n<p>\nLet&#8217;s look at the spec.\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nA function member is said to be an\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa691337(v=VS.71).aspx\">\n<i>applicable function member<\/i><\/a>\nwith respect to an argument list <code>A<\/code> when all of the following\nare true:\n<\/p>\n<ul>\n<li>The number of arguments in&nbsp;<code>A<\/code>\n    is identical to the number of parameters in the function member\n    declaration.<\/p>\n<li>For each argument in&nbsp;<code>A<\/code>,\n    [blah blah blah], and<\/p>\n<ul>\n<li>for a value parameter or a parameter array, an\n        <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa691280(v=vs.71).aspx\">\n        implicit conversion<\/a> exists from the type of the argument\n        to the type of the corresponding parameter, or<\/p>\n<li>[blah blah blah]\n    <\/ul>\n<\/ul>\n<p>\nFor a function member that includes a parameter array,\nif the function member is applicable by the above rules,\nit is said to be applicable in\n<i>normal form<\/i>.\nIf a function member that includes a parameter array is not\napplicable in its normal form,\nthe function member may instead be applicable in its\n<i>expanded form<\/i>:\n<\/p>\n<p>\n&#8230;\n<\/p>\n<\/blockquote>\n<p>\n(I removed some text not relevant to the discussion.)\n<\/p>\n<p>\nNote that the language specification prefers normal form over\nexpanded form:\nIt considers expanded form only if normal form does not apply.\n<\/p>\n<p>\nOkay, so what if you want that call to be applied in expanded form?\nYou can simulate it yourself,\nby manually performing the transformation that the compiler\nwould do:\n<\/p>\n<pre>\n  public static void Main() {\n   Sample(<font COLOR=\"blue\">new object[] {<\/font> new object[] { \"hello\", \"there\" } <font COLOR=\"blue\">}<\/font>);\n  }\n<\/pre>\n<p>\nYes, it&#8217;s extra typing.\nSorry.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If a parameter to a C# method is declared with the params keyword, then it can match either itself or a comma-separated list of um itselves(?). Consider: class Program { static void Sample(params int[] ints) { for (int i = 0; i &lt; ints.Length; i++) { System.Console.WriteLine(&quot;{0}: {1}&quot;, i, ints[i]); } System.Console.WriteLine(&quot;&#8212;&#8211;&quot;); } public static [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-3603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If a parameter to a C# method is declared with the params keyword, then it can match either itself or a comma-separated list of um itselves(?). Consider: class Program { static void Sample(params int[] ints) { for (int i = 0; i &lt; ints.Length; i++) { System.Console.WriteLine(&quot;{0}: {1}&quot;, i, ints[i]); } System.Console.WriteLine(&quot;&#8212;&#8211;&quot;); } public static [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=3603"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3603\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=3603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=3603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=3603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}