Search code examples
c#lambda.net-8.0

Discard variable in Lambda with discarded lambda parameter


I'm using .NET 8.0, and have a problem with a discard variable.

Here's a minimal example:

using System;
using System.Threading.Tasks;

public static class Program
{
    public static void Main()
    {
        DoThing((_, x) => // << Changing this line to discard both parameters fixes it.
        {
            _ = DoNothingAsync(); // << compile error here
        });
    }

    private static void DoThing(Action<int, int> action)
    {
        action(1, 2);
    }

    private static async Task<int> DoNothingAsync()
    {
        await Task.Delay(200);
        return 42;
    }
}

This causes a compiler error on the the line marked above.

Changing the previous commented bit to discard both lambda parameters fixes it, but I need the parameter.

It seems the first discard knows it's type and won't let me discard another variable in the lambda body.

Is this a compiler bug? Am I misunderstanding something?


Solution

  • It's to preserve compatibility with old codes, written before introducing discards, where (_, x) => had a different meaning: one parameter was named _ and the other x.

    If you look the syntax highlighting closely (well, at least in Visual Studio), you can notice that the coloring is different in these cases:

    enter image description here

    vs.

    enter image description here

    In the first case the blue _ indicates that it's a contextual keyword, whereas in the 2nd case the _ is yellow, indicating that it's the first parameter now. The CS0029 error also supports this:

    Cannot implicitly convert type 'System.Threading.Tasks.Task<int>' to 'int'
    

    In the first case we can be sure that this won't break any old code, because two parameters cannot have the same name. And please also note that you can fix the code also by naming both parameters correctly, so the _ in the _ = DoNothingAsync() line can be interpreted as a discard again:

    public static void Main()
    {
        DoThing((x, y) => // << Naming both parameters fixes it, too.
        {
            _ = DoNothingAsync(); // << no error, the highlight is blue again
        });
    }