Why Can't C# Use Inline Anonymous Lambdas or Delegates

Why can't c# use inline anonymous lambdas or delegates?

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

  • Lambda vs Anon - Part One
  • Lambda vs Anon - Part Two
  • Lambda vs Anon - Part Three
  • Lambda vs Anon - Part Four
  • Lambda vs Anon - Part Five

Why can't an anonymous class have a lambda property, but it can have a Func property?

Because there is no way for the compiler to know the type of () => { return 5; }; it could be a Func<int>, but it could also be any other delegate with the same signature (it could also be an expression tree). That's why you have to specify the type explicitly.

Why can't an anonymous method be assigned to var?

UPDATE: This answer was written over ten years ago and should be considered to be of historical interest; in C# 10 the compiler will infer some delegate types.


Others have already pointed out that there are infinitely many possible delegate types that you could have meant; what is so special about Func that it deserves to be the default instead of Predicate or Action or any other possibility? And, for lambdas, why is it obvious that the intention is to choose the delegate form, rather than the expression tree form?

But we could say that Func is special, and that the inferred type of a lambda or anonymous method is Func of something. We'd still have all kinds of problems. What types would you like to be inferred for the following cases?

var x1 = (ref int y)=>123;

There is no Func<T> type that takes a ref anything.

var x2 = y=>123;

We don't know the type of the formal parameter, though we do know the return. (Or do we? Is the return int? long? short? byte?)

var x3 = (int y)=>null;

We don't know the return type, but it can't be void. The return type could be any reference type or any nullable value type.

var x4 = (int y)=>{ throw new Exception(); }

Again, we don't know the return type, and this time it can be void.

var x5 = (int y)=> q += y;

Is that intended to be a void-returning statement lambda or something that returns the value that was assigned to q? Both are legal; which should we choose?

Now, you might say, well, just don't support any of those features. Just support "normal" cases where the types can be worked out. That doesn't help. How does that make my life easier? If the feature works sometimes and fails sometimes then I still have to write the code to detect all of those failure situations and give a meaningful error message for each. We still have to specify all that behaviour, document it, write tests for it, and so on. This is a very expensive feature that saves the user maybe half a dozen keystrokes. We have better ways to add value to the language than spending a lot of time writing test cases for a feature that doesn't work half the time and doesn't provide hardly any benefit in cases where it does work.

The situation where it is actually useful is:

var xAnon = (int y)=>new { Y = y };

because there is no "speakable" type for that thing. But we have this problem all the time, and we just use method type inference to deduce the type:

Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });

and now method type inference works out what the func type is.

What's the difference between anonymous methods (C# 2.0) and lambda expressions (C# 3.0)?

The MSDN page on anonymous methods explains it

In versions of C# before 2.0, the only
way to declare a delegate was to use
named methods. C# 2.0 introduced
anonymous methods and in C# 3.0 and
later, lambda expressions supersede
anonymous methods as the preferred way
to write inline code. However, the
information about anonymous methods in
this topic also applies to lambda
expressions. There is one case in
which an anonymous method provides
functionality not found in lambda
expressions. Anonymous methods enable
you to omit the parameter list, and
this means that an anonymous method
can be converted to delegates with a
variety of signatures. This is not
possible with lambda expressions. For
more information specifically about
lambda expressions, see Lambda
Expressions (C# Programming Guide).

And regarding lambda expressions:

A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types.
All lambda expressions use the lambda operator =>, which is read as "goes to". The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block. The lambda expression x => x * x is read "x goes to x times x." This expression can be assigned to a delegate type as follows:

Why must a lambda expression be cast when supplied as a plain Delegate parameter

A lambda expression can either be converted to a delegate type or an expression tree - but it has to know which delegate type. Just knowing the signature isn't enough. For instance, suppose I have:

public delegate void Action1();
public delegate void Action2();

...

Delegate x = () => Console.WriteLine("hi");

What would you expect the concrete type of the object referred to by x to be? Yes, the compiler could generate a new delegate type with an appropriate signature, but that's rarely useful and you end up with less opportunity for error checking.

If you want to make it easy to call Control.Invoke with an Action the easiest thing to do is add an extension method to Control:

public static void Invoke(this Control control, Action action)
{
control.Invoke((Delegate) action);
}

Cannot convert lambda expression to type ... because it is not a delegate type

If you want an Anonymous Method, you'll have to declare one which returns a Task<Session> as it is marked with the async modifier, hence must return a void (only for async event handlers), Task or Task<T> :

Func<Task<Session>> anonFunction = async () => await fileService.ReadJsonAsync();

If all you do is run ReadJsonAsync, you may also save yourself the state machine generation like so:

Func<Task<Session>> anonFunction = fileService.ReadJsonAsync;

Then you can await on it higher up the call stack:

Func<Task<Session>> anonFunction = fileService.ReadJsonAsync;
await anonFunction();

C# - Anonymous delegate

Your delegate collection in the example points to a number of anonymous methods. A delegate is "just a method pointer". It doesn't matter if it points to a real method or an anonymous method.

Please see http://msdn.microsoft.com/en-us/library/0yw3tz5k(VS.80).aspx



Related Topics



Leave a reply



Submit