Wait for a static value to appear In my program I need to monitor the state of a static string value that can be changed from different threads in different parts of the system. I came up with the following simple function that, once called, waits 5 seconds to get the value, and if the value is not set, returns null:

// Waits 5 seconds for value to appear and returns this value or null
public async Task&lt;string&gt; GetStringValueOrNull()
{
    var delayTask = Task.Delay(5000);
    var getValueTask = Task.Run(async () =&gt; 
    {
        while (true)
        {
            if (!string.IsNullOrEmpty(ExternalValueContainer.Value)) // ExternalValueContainer.Value is 'public static string'
                return ExternalValueContainer.Value;
            await Task.Delay(500);
        }
    });

    var firstCompletedTask = await Task.WhenAny(getValueTask, delayTask);
    if (firstCompletedTask == getValueTask)
    {
        return await getValueTask;
    }
    else
    {
        return null;
    }
}


The function is used like this:

string stringValue = await GetStringValueOrNull();
if (stringValue != null)
    DoSomething(stringValue);
else
    DoSomethingElse();


Can the logic in GetStringValueOrNull be somehow simplified?
Some other improvements:


Check ExternalValueContainer.Value synchronously first. If it already exist then you can return early, and there is no reason to await anything. (Note eurotrash's point about thread safety).
If value is never set, getValueTask never returns. Instead of waiting for delayTask separately, you should check the timeout inside getValueTask's body and return once timeout is exceeded.


In general I feel like proper unit tests should not use delays and should not rely on them. Not only because those 5s delays quickly add up if you run this method multiple times, but also because the behavior of unit tests becomes unpredictable. The same test can fail on one machine and pass on another, simply because on one machine GetStringValueOrNull() timed out, while on the other - it did not. IMHO you should take it as signal, that you design is flawed and should be changed. If you own ExternalValueContainer, then you should probably modify its API so consumer can wait for the value (using async methods, events, observables or any other suitable tool). If you do not own ExternalValueContainer then you should wrap it in non-static service and mock this service in your tests.