Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>EDIT: Eric Lippert's answer describes (<strong>much</strong> better) the issue - please see his answer for the 'real deal'</p> <p>FINAL EDIT: As unflattering as it is for one to leave a public demonstration of their own ignorance in the wild, there's no gain in veiling ignorance behind a push of the delete button. Hopefully someone else can benefit from my quixotic answer :) </p> <p>Thanks Eric Lippert and svick for being patient and kindly correcting my flawed understanding! </p> <hr> <p>The reason that you are getting the 'wrong' error message here is because of variance and compiler-inference of types combined with how the compiler handles type resolution of named parameters</p> <p>The type of the prime example <code>() =&gt; Console.LineWrite( "42" )</code> </p> <p>Through the magic of type inference and covariance, this has the same end result as </p> <p><code>Foo( bar: delegate { Console.LineWrite( "42" ); } );</code></p> <p>The first block could be either of type <code>LambdaExpression</code> or <code>delegate</code>; which it is depends on usage and inference.</p> <p>Given that, is it no wonder that the compiler gets confused when you pass it a parameter that's supposed to be an <code>Action</code> but which could be a covariant object of a different type? The error message is the main key that points toward type resolution being the issue.</p> <p>Let's look at the IL for further clues: All of the examples given compile to this in LINQPad:</p> <pre><code>IL_0000: ldsfld UserQuery.CS$&lt;&gt;9__CachedAnonymousMethodDelegate1 IL_0005: brtrue.s IL_0018 IL_0007: ldnull IL_0008: ldftn UserQuery.&lt;Main&gt;b__0 IL_000E: newobj System.Action..ctor IL_0013: stsfld UserQuery.CS$&lt;&gt;9__CachedAnonymousMethodDelegate1 IL_0018: ldsfld UserQuery.CS$&lt;&gt;9__CachedAnonymousMethodDelegate1 IL_001D: call UserQuery.Foo Foo: IL_0000: ldarg.0 **IL_0001: callvirt System.Action.Invoke** IL_0006: ret &lt;Main&gt;b__0: IL_0000: ldstr "42" IL_0005: call System.Console.WriteLine IL_000A: ret </code></pre> <p>Note the ** around the call to <code>System.Action.Invoke</code>: <code>callvirt</code> is exactly what it seems like: a virtual method call. </p> <p>When you call <code>Foo</code> with a named argument, you're telling the compiler that you're passing an <code>Action</code>, when what you're <strong>really</strong> passing is a <code>LambdaExpression</code>. Normally, this is compiled (note the <code>CachedAnonymousMethodDelegate1</code> in the IL called after the ctor for <code>Action</code>) to an <code>Action</code>, but since you explicitly told the compiler you were passing an action, it attempts to use the <code>LambdaExpression</code> passed in as an <code>Action</code>, instead of treating it as an expression!</p> <p>Short: named parameter resolution fails because of the error in the lambda expression (which is a hard failure in and of itself)</p> <p>Here's the other tell:</p> <pre><code>Action b = () =&gt; Console.LineWrite("42"); Foo(bar: b); </code></pre> <p>yields the expected error message.</p> <p>I'm probably not 100% accurate on some of the IL stuff, but I hope I conveyed the general idea</p> <p>EDIT: dlev made a great point in the comments of the OP about the order of overload resolution also playing a part. </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