Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange Behaviour Using Delegates and Lambdas

As a means of introducing lazy formatting evaluation in a library I am developing, I have defined the delegates

public delegate string MessageFormatterDelegate(string message, params object[] arguments);
public delegate string MessageFormatterCallback(MessageFormatterDelegate formatterDelegate);

and something along the lines of the following class

public static class TestClass
{
    public static string Evaluate(MessageFormatterCallback formatterCallback)
    {
        return (formatterCallback(String.Format));
    }
}

However, this is behaving strangely enough: when running from an external project, the statement

Console.WriteLine(TestClass.Evaluate(message => message("{0},{1},{2}", 1, 2, 3)));

does not compile, failing with the error

Error   1   Delegate 'MessageFormatterDelegate' does not take 4 arguments

while

Console.WriteLine(TestClass.Evaluate((MessageFormatterDelegate message) => message("{0},{1},{2}", 1, 2, 3)));

compiles and works with no problems, printing 1,2,3 in the console. Why do I have to qualify the message argument with MessageFormatterDelegate type in the second lambda expression? Is there any way to circunvent this behaviour?

like image 312
DotNetStudent Avatar asked Feb 03 '12 11:02

DotNetStudent


2 Answers

UPDATE:

The bug has been fixed in C# 5. Apologies again for the inconvenience, and thanks for the report.


This appears to be a duplicate of the known bug described here:

'Delegate 'System.Action' does not take 0 arguments.' Is this a C# compiler bug (lambdas + two projects)?

See my answer to that question for details.

It was also reported here:

C# Parser Bug on delegate?

This bug was my bad; I apologize for the error. We'll try to get a fix in C# 5.

If you think that you have actually found a different bug, please let me know and we'll start an investigation.

And thanks for the report, I appreciate it.

like image 161
Eric Lippert Avatar answered Oct 04 '22 03:10

Eric Lippert


EDIT: Okay, I've now got a much shorter example and a workaround.

First source file, External.cs:

public delegate string Callback(System.Action<string> x);

Second source file, Test.cs:

class Test
{
    static void Main()
    {
        Callback callback = action => action("hello");
    }
}

Compile with:

> csc /target:library External.cs
> csc Test.cs /r:External.cs

Error:

Delegate 'Action' does not take 1 arguments

Workaround: change the body of the Main method to:

Callback callback = action => action.Invoke("hello");

... or include the delegate declaration in the same assembly which uses it.

This definitely looks like a bug to me. When the compiler knows that the type of foo is a particular delegate type, then foo(arg) and foo.Invoke(arg) should be equivalent.

Will mail Eric Lippert...

like image 39
Jon Skeet Avatar answered Oct 04 '22 02:10

Jon Skeet