1

I have been trying to figure this out and it's really bugging me. I have some code that looks like this

static T MyFunction<T>(Func<T> action, int i, int i2)
{
    ...some code here
}

When I need to call this code I tried this

var result = MyFunction<List<string>>(MethodThatReturnsListofString(int number), 1,2)

It fails stating that the best overload has invalid arguments But when I tried the following

var result = MyFunction<List<string>>(() => MethodThatReturnsListofString(int number), 1,2)

It works fine. What is the function of "() =>" in this case. I thought() could not be used with methods required more than 0 args.

Rocky
  • 182
  • 1
  • 1
  • 9
  • 4
    `MethodThatReturnsListofString(int number)` makes no sense; you're passing a parameter, not declaring a function. Please show actual code. – SLaks Feb 18 '16 at 16:41
  • `Func action` ... – leppie Feb 18 '16 at 16:42
  • My apologies, I was trying to make my question clearer and may have obscured the issue in trying to do so. MethodTheReturnsListOfString takes a single integer argument. – Rocky Feb 18 '16 at 16:43

4 Answers4

5

You're passing a lambda that takes no arguments.
That is the correct syntax to write such a lambda.

The fact that your lambda happens to call a function that takes arguments is completely irrelevant.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Perhaps my fundamental understanding of Lambda is incorrect. What part of the call I am making is considered the lambda? To attempt to make my question more clear, you say I am passing a lambda that takes no arguments. what part of my "correct" call is that lambda? – Rocky Feb 18 '16 at 16:46
  • Yes; you are misunderstanding things. The lambda consists of the parameters prefix (`() =>`) and the body that specifies the return value (in your case, a function call). – SLaks Feb 18 '16 at 16:48
  • So `() =>` is just a placeholder for a method that doesn't really exist, that takes no arguments, and returns, in my case, the result of the method call to `MethodThatReturnsListOfString(int)`?? – Rocky Feb 18 '16 at 16:57
  • 1
    @Rocky: It isn't a placeholder; it's the syntax to declare a nested method. Read the documentation. – SLaks Feb 18 '16 at 16:58
  • I actually have read the docs, I just found them a bit confusing. Thank you for helping me to understand a bit better though. So the `() => ` doesn't "hold" and place, it instead declares an anonymous method on the fly that will contain and return the result of the method called on the right side of the lambda expression, regardless of the number of arguments that second method happens to call. This works because the lambda takes no actual arguments, thus fulfilling the requirement of `Func action`. correct? – Rocky Feb 18 '16 at 17:03
4

MyFunction<T> expects as first parameter a method that takes no arguments and returns the type T.

In your first attempt, you call MethodThatReturnsListofString(number) and try to provide the result (a List<T>) as parameter instead of a method.

In your second try, you create a method with the required signature by typing () => MethodThatReturnsListofString(number) and provide this as parameter.


To make it more clear, you could have created a method like

static List<T> MyAnonymousMethod()
{
    return MethodThatReturnsListofString(number);
}

and then called

MyFunction<List<string>>(MyAnonymousMethod, 1, 2);

With () => MethodThatReturnsListofString you declare an anonymous method inline and so you don't need to create MyAnonymousMethod first. This part of your code is what is called a lambda expression.


Note that by declaring this lambda, MethodThatReturnsListofString is not executed immediatly! It will be executed only when MyFunction really calls this action parameter like

static T MyFunction<T>(Func<T> action, int i, int i2)
{
    // ... some code
    var result = action();
    // ... more code
}
René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • So I'm creating an anonymous method that takes no arguments, to hold the result of a method that takes a number? – Rocky Feb 18 '16 at 16:53
  • @Rocky Indeed. Note that when `MyFunction` actually calls this `action`, the then current value of `number` will be used. This may already differ from the value it had when calling `MyFunction` – René Vogt Feb 18 '16 at 16:56
  • Ah. I can probably account for that by being careful how I manipulated the value of number while it is being called. – Rocky Feb 18 '16 at 17:07
3

This simply means that you are invoking an anonymous method which accepts 0 arguments. If its () => a+b

it returns the addition

else if you provide it a body

like ()=> { } its upto you to return or not

also if you provide the delegate which needs it to return then you have to return. for eg Action doesnt require but Func do require

1
MethodThatReturnsListofString(number)

is not a Func<T>. It is a Func<T, U>, where List<string> is one type argument and int is the other. Moreover, you are providing the result of this method — not the method itself — as the argument to your function.

On the other hand, this expression is a Func<T>:

() => MethodThatReturnsListofString(number)

This is a lambda expression that creates a delegate with no input parameters and one output parameter (the List<string>). The number variable passed to MethodThatReturnsListofString() is not part of the function definition. The code works because the number variable is instead a closure. The variable is captured by the compiler and used by the method, but it's not part of the method signature.

I thought () could not be used with methods required more than 0 args.

That is correct. But remember that the Func<T> type used for your action argument here defines a function that accepts 0 arguments and returns one value. So what you are doing is matching your expression to the Func<T> type of MyFunction's action parameter. Just because you then call a method that requires an argument within your new Func<T> delegate doesn't mean the delegate itself requires an argument.

Community
  • 1
  • 1
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794