TheColonel26
TheColonel26

Reputation: 2728

Return a Task from a method with type void

I would like to create a task to run serial commands on. At this time I do not need to return anything from the method that is doing the work. This will probably change later, but I am now curious as to how this.

This is what I have. I would like to use a separate method for the task instead of creating an anonymous action. I have tried returning void, with the result of "void can not be explicitly converted to a Task". I have also tried. Task<void>. The Last thing I have tried is returning a Task, but I receive, error "Not all Code paths return a value" and "Can not implicily convert void to type task"

enter image description here

In the pass I have used a Thread to accomplish this, but I'd like to use Tasks this time around.

internal class Hardware
{
    private EventHandler<SequenceDoneEventArgs> SequenceDone;

    private List<Step> Steps;
    private System.IO.Ports.SerialPort comport = null;

    private Task SequenceTask;
    private CancellationTokenSource RequestStopSource;
    private CancellationToken RequestStopToken;


    private void Initialize()
    {
        comport = new System.IO.Ports.SerialPort("COM2", 115200, System.IO.Ports.Parity.None,8);
        comport.DataReceived += Comport_DataReceived;
    }

    public async void RunSequence()
    {
        if (comport == null)
        {
            Initialize();
        }
        if (!comport.IsOpen)
        {
            comport.Open();
        }

        RequestStopSource = new CancellationTokenSource();
        RequestStopToken = RequestStopSource.Token;

        SequenceTask = await Task.Run(() => { doSequence(); });

    }

    private Task doSequence()
    {
        //** Run Sequence stuff here

    }
}

ETA:

In the end this is my the complete solution

internal class Hardware
{
    private EventHandler<SequenceDoneEventArgs> SequenceDone;

    private List<Step> Steps;
    private System.IO.Ports.SerialPort comport = null;

    private Task SequenceTask;
    private CancellationTokenSource RequestStopSource;
    private CancellationToken RequestStopToken;


    private void Initialize()
    {
        comport = new System.IO.Ports.SerialPort("COM2", 115200, System.IO.Ports.Parity.None,8);
        comport.DataReceived += Comport_DataReceived;
    }

    public async void RunSequence()
    {
        if (comport == null)
        {
            Initialize();
        }
        if (!comport.IsOpen)
        {
            comport.Open();
        }

        RequestStopSource = new CancellationTokenSource();
        RequestStopToken = RequestStopSource.Token;

        SequenceTask = await Task.Factory.StartNew(async () => { await doSequence(); });

    }

    private Task doSequence()
    {
        //** Run Sequence stuff here

        //return null;
        return Task.CompletedTask;
    }
}

Upvotes: 6

Views: 20194

Answers (2)

Dominik
Dominik

Reputation: 1741

SequenceTask = await Task.Factory.StartNew(async() => { await doSequence(); });

Also your RunSequence() should return Task instead of void.

Actually if you await the Task this should result in the same:

SequenceTask = await doSequence();

Upvotes: 2

Stephen Cleary
Stephen Cleary

Reputation: 456387

Just mark doSequence as async (assuming it uses await):

private async Task doSequence()

Also, it's a good idea to return this Task in the delegate you pass to Task.Run:

SequenceTask = await Task.Run(() => doSequence());

I would like to create a task to run serial commands on.

This leads me to believe that using async and Task may not be the best solution for your scenario. I suggest you look into TPL Dataflow.

Upvotes: 7

Related Questions