Why can't c# use inline anonymous lambdas or delegates? [duplicate]
Asked Answered
A

4

33

I hope I worded the title of my question appropriately.

In c# I can use lambdas (as delegates), or the older delegate syntax to do this:

Func<string> fnHello = () => "hello";
Console.WriteLine(fnHello());

Func<string> fnHello2 = delegate()
{
    return "hello 2";
};
Console.WriteLine(fnHello2());

So why can't I "inline" the lambda or the delegate body, and avoid capturing it in a named variable (making it anonymous)?

// Inline anonymous lambda not allowed
Console.WriteLine(
    (() => "hello inline lambda")()
);

// Inline anonymous delegate not allowed
Console.WriteLine(
    (delegate() { return "hello inline delegate"; })()
);

An example that works in javascript (just for comparison) is:

alert(
    (function(){ return "hello inline anonymous function from javascript"; })()
);

Which produces the expected alert box.

UPDATE: It seems you can have an inline anonymous lambda in C#, if you cast appropriately, but the amount of ()'s starts to make it unruly.

// Inline anonymous lambda with appropriate cast IS allowed
Console.WriteLine(
    ((Func<string>)(() => "hello inline anonymous lambda"))()
);

Perhaps the compiler can't infer the sig of the anonymous delegate to know which Console.WriteLine() you're trying to call? Does anyone know why this specific cast is required?

Anaerobic answered 22/4, 2010 at 2:47 Comment(1)
Consider this: public static R Eval<R>(Func<R> m){return m();}. You can then say Eval<string>(()=>{return "test";}) which is a little nicer, or even Eval(()=>{return "test";}).Gearing
K
27

Lambdas in C# do not have types, until they are used in a context that casts them to a delegate or Expression type.

That's why you cannot do the following:

var x = () => "some lambda";

You might enjoy Eric Lippert's Series on Lambda Expressions vs Anonymous Methods

Keown answered 22/4, 2010 at 2:51 Comment(3)
+1. Important basic concept regarding lambdas in C#.Cotyledon
This may change in C# 10 learn.microsoft.com/en-us/dotnet/csharp/language-reference/…Brucebrucellosis
We can do it since C# 10 var x = () => "some lambda";Virnelli
D
17

It seems to work if you give it a type cast:

String s = ((Func<String>) (() => "hello inline lambda"))();

Is it useless? Not entirely. Take the below:

String s;
{
    Object o = MightBeNull();
    s = o == null ? "Default value" : o.ToString();
}

Now consider this:

String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString())
    )(MightBeNull());

It's a little ugly, but it is compact.

Deplume answered 14/11, 2012 at 14:29 Comment(2)
I loved it. Playing with XUnit and Fluent Assertions it was possible to use this inline capability in a way I find really cool.Ragg
I shared the code here =)Ragg
G
10

When you write Func<string> = ..., the compiler knows that it has to create an object of type Func<string>. But when you write that delegate inline, the compiler doesn't know object of which type it has to create.

Having said the above, an obvious conclusion can be drawn: just tell the compiler the type explicitly!

Console.WriteLine( new Func<string>( () => "Hello" )() );

UPDATE

Ok, while I was writing the answer, you updated your post. I believe my answer above already answers the question "why this specific type is required". To reiterate: because the compiler doesn't know object of which type to create.

Now to elaborate a bit on the "the compiler can't infer the sig of the anonymous delegate" part. You see, it's not like in JavaScript. In C#, there's no generic "function" (or "method") type. Each delegate must have an explicitly specified signature and type name. And when you're creating a delegate, the compiler must know what type.

Now, I can see how you may imply that the compiler could just construct a delegate type on the fly, like it does with anonymous object types (aka new { a = 1, b = "xyz" }). But think about it for a moment: there would be probably no use for such delegate anyway. I mean, you can't pass it to another method, because that method has to declare types of it's arguments first. And you can't make an event out of it, because, again, you must have a named type.

Something like that...

Glia answered 22/4, 2010 at 3:10 Comment(0)
L
2

You can use inline lambda expressions for methods that take in a Delegate parameter.

However there is a slight catch - if the parameter is typed as the base Delegate type, you'd need to explicitly cast it to a specific derivation of Delegate (say Action) ; else the compiler would complain.

Similar questions:
Anonymous method in Invoke call
Anonymous methods and delegates

Logbook answered 22/4, 2010 at 3:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.