John Darvill
John Darvill

Reputation: 1303

C#.Net Delegates

Say I have a method that calls another method that accepts a string and returns a string, over and over until a condition is met:

public string RetryUntil(
    Func<string, string> method,
    string input,
    Func<string, bool> condition,
    TimeSpan timeSpan)
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    string response = string.Empty;
    bool conditionResult = false;

    while (stopwatch.Elapsed < timeSpan && conditionResult != true)
    {
        result = method(input);
        conditionResult = condition(result);
        Thread.Sleep(TimeSpan.FromSeconds(0.5));
    }

    return response;
}

It really feels like I should be able to specify the 'method' and 'input' parameters as one parameter. So, I want to refactor it so I am able to call it like this, for example:

RetryUntil(
    ConvertString("hello World"),
    (str) => { return str == "whatever"; },
    TimeSpan.FromSeconds(10));

But obviously, this would pass the result of calling the ConvertString method, (rather than just a delegate to that method) into the Retry method. Is there a way to pass both delegates and specific parameters for those delegates as one? Am I thinking about the entire problem backwards? It just feels a bit inelegant the way I'm doing it now.

Upvotes: 3

Views: 83

Answers (1)

David
David

Reputation: 10708

What you're looking for is often called "currying" and is not directly supported in C#, or at least not as well as it is in F#. This is a feature where you can specify some arguments of a function, and get a delegate which takes the remaining arguments (if any) and returns the appropriate value.

The easiest way to reference this is like so:

public string RetryUntil(
    Func<string> method,
    Func<string, bool> condition,
    TimeSpan timeSpan)

And then call via

RetryUntil(
    () => ConvertString("Hello World!"),
    // ...

the => creates a lambda, which will return the result of the given function. Since you're now declaring a method call, you can pass in whatever parameters you wish, or make the lambda itself take some parameters, thus currying arguments.

Upvotes: 3

Related Questions