What's the method signature for passing an async delegate?
Asked Answered
R

4

88

I've recently moved back to C# from being in Objective-C land, and the async/await keywords in C# 5 look cool. But I'm still trying to get a handle on the proper syntax.

I want to declare a method that takes an asynchronous delegate as a parameter, but I am having trouble getting both the caller and the callee syntax correct. Can someone provide a code sample showing the method declaration, the call, and a call to the delegate?

I'm thinking the declaration would be something like the following. Note that this function isn't asynchronous; i.e. its asynchronicity is independent of the delegate.

void DoSomethingWithCallback(async delegate foo(int)) 
{
    ...
    foo(42);
    ...
}

The call would be something like:

DoSomethingWithCallback(async (int x) => { this.SomeProperty = await SomeAsync(x); });

Of course none of this compiles and most of the samples I've seen assume that one has a field or property that's the delegate, rather than the anonymous delegate I'd like to use.

Rutaceous answered 14/12, 2011 at 20:51 Comment(1)
as near as I can tell, there's no way to specify a delegate inline, as I do in the question above. To use a delegate as a method parameter, a delegate type needs to be declared outside of class scope.Rutaceous
R
107

A function that takes a delegate as a parameter must use a named delegate type; unlike in Objective-C you can't declare an anonymous delegate type inline in the function definition. However, the generics Action<> and Func<> are provided so that you don't have to declare a new type yourself. In the code below I'm assuming the delegate takes a single int as a parameter.

void DoSomethingWithCallback(Func<int,Task> callbackDelegate)
{
    Task t = callbackDelegate(42);
}

If this function doesn't actually do anything with the Task object returned (as with the code shown above), you can instead use Action<int> as the delegate type. If you use Action, you can still declare the delegate async (below) but the implicit Task object returned is ignored.

The lambda syntax for calling the above function is straightforward and the syntax you used in the question is correct. Note that the parameter type doesn't need to be specified here since it can be inferred:

DoSomethingWithCallback(async (intParam) => { this.myint = await Int2IntAsync(intParam); });

You can also pass a method or delegate variable, if you wish, instead of using the lambda syntax:

async Task MyInt2Int(int p) { ... }
Func<int,Task> myDelegate;
void OtherMethod()
{
    myDelegate = MyInt2Int;
    DoSomethingWithCallback(myDelegate); // this ...
    DoSomethingWithCallback(MyInt2Int);  // ... or this.
}
Rutaceous answered 15/12, 2011 at 19:0 Comment(0)
S
16

If I have a task that I want to be passed but not executed, I can wrap the Task in a Func<>, then call that Func<> to create that task. The await can be used in the normal way.

public class Example {
    public Example(Func<Task> toBeExecutedInTheFuture)
    {
        FutureTask = toBeExecutedInTheFuture;
    }

    public async void ExecuteTaskExample()
    {
        await FutureTask();

        // or alternatively

        var myTask = FutureTask();
        // do work
        await myTask;
    }
}
Swart answered 16/6, 2020 at 16:22 Comment(0)
I
11

The return type of the method signatue is Task if there is no return type, or Task<T> if there is a return type.

Tho, I'm not 100% certain if you can have async lambdas like that.

In the method that is consuming the task, you would either 'await' the task or use the properties and methods on Task to get the result.

Insanity answered 14/12, 2011 at 20:53 Comment(1)
Yes, we are supporting async lambdas. Pretty slick if I do say so myself.Sheepwalk
J
-2

Please take a look to this example, with Task and an additional parameter. I hope this can help people understanding how to implement it...

// ... more code ...

// Let's call a function with a Task<T> parameter (LocalFunc)
await CustomFunctionAsync(                                       
    param1,
    LocalFunc
    );

// ... more code ...

Declared functions:

public static async Task CustomFunctionAsync(int param1, Func<string, Task<string>> processingFunc = null)
{
    string result = null;
    if (processingFunc != null)
        result = await processingFunc("https://www.google.com/");
}

public async Task<string> LocalFunc(string url)
{
    // processing...
}
Janenejanenna answered 16/12, 2021 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.