Can I ignore delegate parameters with lambda syntax?
Asked Answered
C

7

31

I am curious why C# allows me to ignore delegate parameters in some cases but not others.

For instance this is permitted:

Action<int> action = delegate { Console.WriteLine("delegate"); };

but this is not:

Action<int> action = () => Console.WriteLine("lambda");

Is there a way to initialize a delegate and ignore the parameters using a lambda? I know that I can add a single parameter to the lambda and fix the previous line but this is more of an academic question pertaining to the compiler and why or how this works.

Clemmie answered 3/2, 2009 at 2:34 Comment(0)
J
20

I believe that your first sample actually creates an anonymous function that is able to take on many different signatures whose body is the single statement Console.WriteLine.... Because it can match different signatures, it does not cause a problem. In the second sample, the lambda syntax itself defines a function that takes no parameters with the same body. Obviously the latter is not consistent with the defined Action so you get the error.

C# Anonymous Method Reference

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.

Joyjoya answered 3/2, 2009 at 3:5 Comment(4)
Whether this is right or not depends on how you read the answer. The generated IL is definitely for only a method taking an int. The compiler has to know the compile-time type it's trying to convert it to - if you change the signature of action to just "Delegate" you'll get a compile-time error.Helbonia
What I meant (and thought I said) was by omitting the parameter list from the delegate in the first sample, the compiler "fills it in" when creating the method so that it does match the required signature. Lambda expressions don't allow you to omit the parameter list -- an empty list infers a method with no parameters -- and so causes a compile-time error.Joyjoya
@JonSkeet the following code compiles and executes successfully even while using delegate definition in place of action - public delegate void MyFun(int i); private static void TestJonsArgument() { MyFun fun1 = delegate { Console.WriteLine("Example without Parameters : " + 2); }; fun1.Invoke(20); }Holocaine
@RBT: That's still using the specific delegate type (MyFun) in the declaration. Change MyFun fun1 = ... to Delegate fun1 = ... and it won't compile. It's not which specific delegate that's important - there's nothing magical about Action<T> - it's that it's a particular delegate type rather than just the base class Delegate (or MulticastDelegate).Helbonia
C
8

To elaborate on tvanfosson's answer; this behavior is described in the C# 3.0 language specification (§7.14):

The behavior of lambda-expressions and anonymous-method-expressions is the same except for the following points:

• anonymous-method-expressions permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.

• lambda-expressions permit parameter types to be omitted and inferred whereas anonymous-method-expressions require parameter types to be explicitly stated.

• The body of a lambda-expression can be an expression or a statement block whereas the body of an anonymous-method-expression must be a statement block.

• Since only lambda-expressions can have an expression body, no anonymous-method-expression can be successfully converted to an expression tree type (§4.6).

I think:

Action<int> action = () => Console.WriteLine("lambda");

is the equivalent of:

Action<int> action = delegate() { Console.WriteLine("delegate"); };

which wouldn't compile either. As Daniel Plaisted says () is explicitly saying there aren't any parameters.

If there were an equivalent of delegate{} it might be:

Action<int> action = => Console.WriteLine("lambda")

Which isn't very pretty and I suspect it suspect isn't in the spirit of lambda expressions.

Coeval answered 3/2, 2009 at 4:44 Comment(0)
G
6

As others said, no, you can't skip declaring the parameters to a lambda. But, for cleanliness, I suggest giving them a name such as _. For example

foo.Click += (_,__) => { ... }

You aren't ignoring them per-se, but you're indicating you don't care what they are and will not use them.

Garrek answered 3/2, 2009 at 23:13 Comment(4)
and will confuse the hell out of anyone new to the lambdas, or not familiar with your convention.Woolly
Anyone new to lambdas needs training before they can work on any of our projects anyways. That's a hiring/training/HR issue. I see no benefit in writing to people who'll get confused by simple stuff :).Garrek
I'd suggest dummy1, dummy2, etc. would be better names, since names like _` are sometimes used for meaningful things (e.g. _ = someComplocatedExpression; _.Prop1 = (_.Prop2 + _.Prop3) * (_.Prop4 + _.Prop5) [but with the second expression being even more complicated]. The name _ fairly clearly refers to the thing whose reference was obtained in the line above; the names of the properties are apt to be far more interesting to whoever's reading the code than would be the name given to the temporary variable.Versicular
In this case you are simply better off just using an anonymous method.Mistiemistime
W
2

The () => ... syntax explicitly specifies that the lambda takes no parameters. Perhaps the language could be modified so that () => really meant "Infer the parameters of this lambda for me" in the same way the delegate syntax does, but that would make the language more complicated. When designing new language features, you start at minus 100, and I don't think this one passes the test.

There may also be more technical reasons why this would be difficult to implement (which is probably more in line with what you were asking for, but I doubt the technical reasons drove this decision if it ever came up).

Warthman answered 3/2, 2009 at 2:56 Comment(0)
P
0

I'd say it's to have a forced use of the parameters of the lambda expression.

Take your first example, how would you interact with the passed in value, there's no local representation of it.

Parenthesis answered 3/2, 2009 at 3:1 Comment(0)
L
0

What about this?

Func<int> lamdapointer = () => TwoArgMethodThatReturnsInt(10,20); // the same method cannot be called with the delegate "NoArgmethodThatReturnsInt"


lamdapointer();

Delegate int NoArgmethodThatReturnsInt();
NoArgmethodThatReturnsInt del = NoArgmethodThatReturnsInt; // only this is possible with delegates


public int TwoArgMethodThatReturnsInt(int x,int y)
{
return x + y;
}

public int NoArgmethodThatReturnsInt()
{
return 20;
}
Logical answered 3/4, 2012 at 6:26 Comment(0)
D
0

Actually, delegate {} does not specify any parameters and fits any delegate method signature - therefore it is permitted in your first construcion.

The Lambda expression () => ...; specifically states parameterless delegate, which contradicts the signature required by Action - a delegate with single parameter.

You may want to use one of the following options.

If you need the action to have a parameter, you can do it the next way ("_" is a legal character for identifier name).

Action<int> action = _ => Console.WriteLine("lambda");

Or you may want to use parameterless Action as follows:

Action action = () => Console.WriteLine("lambda");

Discombobulate answered 12/12, 2013 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.