Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Argument binding for the method call <code>firstProcess.Calculate(x: 1, y: 2)</code> is done <em>at compile time</em>, but method dispatch is done <em>at runtime</em> because the method is <code>virtual</code>.</p> <p>In order to compile the method call, the compiler sees <code>x: 1, y: 2</code> and needs to resolve this named argument list to a sequentially indexed argument list in order to emit the appropriate IL (push the arguments on the stack in the right order, then call method).</p> <p>In addition to the named argument list there is one more piece of information available to the compiler: the <em>static</em> type of <code>firstProcess</code>, which is <code>FirstProcess</code>. Now me and you both know that at runtime this is going to be a <code>SecondProcess</code> instance, but the compiler doesn't know that (at least in the general case). So it looks up the parameter list of <code>FirstProcess.Calculate</code> and sees that <code>x</code> is the first argument, <code>y</code> is the second. This makes it compile your code as if you had written</p> <pre><code>firstProcess.Calculate(1, 2); </code></pre> <p>At <em>runtime</em>, the arguments <code>1</code> and <code>2</code> are pushed on the stack and a virtual call is made to <code>Calculate</code>. Of course this ends up calling <code>SecondProcess.Calculate</code>, but the parameter names have not survived the transition to runtime. <code>SecondProcess.Calculate</code> accepts <code>1</code> as its first argument (<code>y</code>) and <code>2</code> as its second argument (<code>x</code>), leading to the observed result.</p> <p>As an aside, this is also what happens when you use default argument values:</p> <pre><code>public class FirstProcess { public virtual void Calculate(int x = 10) { Console.WriteLine("First Process X :{0}", x); } } public class SecondProcess : FirstProcess { public override void Calculate(int x = 20) { Console.WriteLine("Second Process X :{0}", x); } } var secondProcess = new SecondProcess(); var firstProcess = (FirstProcess) secondProcess; secondProcess.Calculate(); // "Second Process X: 20" firstProcess.Calculate(); // "Second Process X: 10" </code></pre> <p>The moral of the story: named and default arguments are convenient, but the way they are (necessarily) implemented leaves you open to unpleasant surprises. Use them when they offer real tangible benefits, not whenever you can.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload