Can params[] be parameters for a lambda expression? [duplicate]
Asked Answered
T

3

16

I've recently started exploring lambda expressions, and a question came to mind. Say I have a function that requires an indeterminate number of parameters. I would use the params keyword to model that variable number of parameters.

My question: can I do something similar with Lambda expressions? For example:

Func<int[], int> foo = (params numbers[]) =>
                       {
                           int result;

                           foreach(int number in numbers)
                           {
                               result += numbers;
                           }

                           return result;
                       }

If so, two sub-questions present themselves - is there a 'good' way to write such an expression, and would I even want to write an expression like this at some point?

Tod answered 26/6, 2012 at 20:1 Comment(6)
I wonder if you can actually call that a Lambda Expression, I think it is an Anonymous method.Muckrake
@YuriyFaktorovich: It's a lambda. The => is the lambda operator.Anthropophagi
@Andrew, I don't think that would work, but again I did not test it. Did you? Also, doing that is not really necessary, you can take a plain array Func<int[], int> func = numbers => { /* ... */ } and call the lambda with func(new[] { 2, 3, 5, 7, 42 });.Vshaped
This code is untested, though I'm not exactly worried about that; I'm seeing if the concept of a lambda that uses a variable number of parameters is viable. In my research through Microsoft's documentation, I found nothing.Tod
@KendallFrey I found the exact definition, it is a Statement Lambda, not an Expression, which requires some specific rules that I think are broken inside those brackets.Muckrake
@Yuriy, you're absolutely right, statement lambdas cannot be converted into expressions... but they're lambdas nonetheless :)Vshaped
S
20

Well, sort of. First, instead of using Func<>, you would need to define a custom delegate:

public delegate int ParamsFunc (params int[] numbers);

Then, you could write a following lambda:

ParamsFunc sum = p => p.Sum();

And invoke it with variable number of arguments:

Console.WriteLine(sum(1, 2, 3));
Console.WriteLine(sum(1, 2, 3, 4));
Console.WriteLine(sum(1, 2, 3, 4, 5));

But to be honest, it is really much more straightforward to stick with built-in Func<> delegates.

Shake answered 26/6, 2012 at 20:13 Comment(0)
P
3

The closest thing that I think you can get would be something like this:

Func<int[], int> foo = numbers[] =>
                       {
                           // logic...
                       }

var result = foo(Params.Get(1, 5, 4, 4, 36, 321, 21, 2, 0, -4));

And have:

public static class Params
{
    public static T[] Get(params T[] arr)
    {
        return arr;
    }
}

But I can't see how that beats a simple new[] {1, 5, 4, 4, ...}

Perforated answered 26/6, 2012 at 20:8 Comment(0)
R
1

There are two things here, the Func<int[], int> generic delegate on the LHS and the lambda expression on the RHS. The former is not possible, since a Func<S, T> delegate is declared like:

public delegate TResult Func<in T, out TResult>(T arg); //ie no params involved

You need your own delegate that accepts params input as shown in accepted answer.

The latter, which is what the question title is about, is not possible as well in C#, but for a reason.

The LHS of an assignment expression is a compile time thing (unless it's dynamic of course but again compiler is aware of it) and its RHS is a run time thing (unless of course in case of consts). The compiler can infer what's typed on LHS, but it gets the values on RHS only during run time, ie when the code is run. When you type this:

Func<int[], int> foo = ....

foo is always considered as Func<int[], int>. It will add a lot of complexity to compiler if it had to decipher RHS. For e.g. if what you're attempting was possible, think about this scenario:

Func<int[], int> foo = (params int[] numbers) =>
                   {
                       int result;

                       foreach(int number in numbers)
                       {
                           result += numbers;
                       }

                       return result;
                   };

//and later at some other place
foo = (int[] numbers) => 0;

//how would you call 'foo' now?

Instead when you write your own delegate that accepts params, you're telling the compiler directly (ie known from LHS).

Of the three features that parameters of a named method support, ie, out/ref, params, optional parameter, lambda expressions (or even the earlier delegate syntax) support only out/ref.

Ratcliff answered 22/12, 2013 at 3:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.