Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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, ...}

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top