Nick Bull
Nick Bull

Reputation: 9876

Async method nevers finishes

I have a form, like below, that accepts a Task<T>, waits for completion and then returns after await by closing the form:

public partial class SomeForm<T> : Form
{
    public T ReturnValue { get; private set; }
    private Task<T> Task { get; set; }

    public SomeForm(string waitingText, Task<T> task)
    {
        InitializeComponent();

        ...

        PerformTask();
    }

    private async void PerformTask()
    {
        ReturnValue = await Task;
        this.Close();
    }
}

However, whilst this method runs happily, it gets to ReturnValue = await Task; and then does not go any further. The method will run normally without being sent to the method and does not delay. I have a feeling it's to do with how I'm using async and await, but I'm new to TPL etc.

Please help me identify what's wrong with the above script, and in identifying why it never returns.

Edit: TaskA was a typo. Here's the Task's method; ImportedFunctions. BS_Robots_LoadDrive(..) is a DllImport of a C++ function, which works just fine synchronously, even on another thread (like in the final snippet), but not with an async paramter.

    public uint LoadDisc()
    {
        uint response = ImportedFunctions.BS_Robots_LoadDrive(DriveLetters[0],
                        (int)BSRobotConstants.BIN_ID_DEFAULT,
                        (int)BSRobotConstants.POSITION_TYPE_INPUTBIN,
                        0);

        switch (response)
        {
            case BSRobotConstants.OK:
            case BSRobotConstants.OK_WITH_MESSAGE:
            case BSRobotConstants.FROMTRAY_NO_DISC:
            case BSRobotConstants.INVALID_DRIVE:
            case BSRobotConstants.INVALID_POSITION:
            case BSRobotConstants.TOTRAY_NO_DISC:
            case BSRobotConstants.TOTRAY_NOT_OPEN:
            case BSRobotConstants.FATAL_ERROR:
                break; 
            case BSRobotConstants.BUSY:

                break;
            case BSRobotConstants.TOTRAY_HAS_DISC:
                RejectDisc();
                response = LoadDisc();
                break;
        }

        return response;
    }

This works:

private async void PerformTask()
{
    Task.Start();
    Task.Wait();

    ReturnValue = Task.Result;
    DialogResult = DialogResult.OK;
}

But the first code snippet doesn't.

Upvotes: 0

Views: 173

Answers (1)

Dustin Kingen
Dustin Kingen

Reputation: 21275

The task does not continue past ReturnValue = await TaskA; because it is not returning. Verify the Task is running and not getting stuck.

To property utility async-await for object construction use an async factory method.

See: How to initialize an object using async-await pattern

public class Form1<T> : Form
{
    public Form1(string waitingText, Task<T> task)
    {
        Task = Execute(task);
        Controls.Add(new Label { Text = waitingText });
    }

    public T ReturnValue { get { return Task.Result; } }
    public Task<T> Task { get; private set; }

    private async Task<T> Execute(Task<T> task)
    {
        var result = await task;
        Close();
        return result;
    }
}

Usage:

var form = new Form1<int>("Hello", Task.Delay(1000).ContinueWith(_ => 1));
form.Show();

var returnValue = await form.Task;
Console.WriteLine(returnValue);

Upvotes: 2

Related Questions