Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it problematic to start a Task in the constructor?

In the Call asynchronous method in constructor? question is no answer that, starts the async Operation in the constructor and store the Task in a member and an awaits it before using the resource:

    public class DeviceAccess
    {
        private readonly Task<Container> containerTask;
        public DeviceAccess(Database database)
        {
            containerTask = GetContainer(database);
        }

        private async Task<Container> GetContainer(Database database)
        {
            var conatinerResponse = await database.CreateContainerIfNotExistsAsync("Device");
            return conatinerResponse.Container;
        }

        public async Task<Device> GetDevice(string deviceId)
        {
            var container = await containerTask;
            return await doSomething(container);
        }
    }

In my case every Operation needs the resource, so I see no advantage to use some lazy loading.

Is it valid to start a async Operation in a constructor or can result this into problems?

like image 950
sschoof Avatar asked Sep 18 '25 22:09

sschoof


1 Answers

The biggest problem I can see here is that [Value]Task[<T>] is an API that enables async, not a promise to be async; just because CreateContainerIfNotExistsAsync is named *Async and returns Task<T> - that doesn't actually mean it is async - it could run synchronously and return a result via Task.FromResult (aka "async over sync"). If you're not concerned about that problem, then fine I guess. But I wonder whether an OpenAsync() method that you call after construction would be more appropriate, i.e.

public class DeviceAccess
{
    private Container _container;
    public DeviceAccess() {}

    public async ValueTask OpenAsync(Database database) {
        if (_container == null)
            _container = await GetContainerAsync(database);
    }

    public async Task<Device> GetDeviceAsync(string deviceId)
    {
        var container = _container ?? throw new InvalidOperationException("not open");
        return await doSomething(container); // might be able to inline the "await" here
    }
}
like image 77
Marc Gravell Avatar answered Sep 21 '25 12:09

Marc Gravell