DiscoveryBlvd

Task-based Asynchronous Pattern (or TAP) was introduced into the .NET framework in version 4, and provided a consistent new pattern for arbitrary asynchronous operations. You have probably already used the Task class to perform an operation on a thread pool thread rather than the main application thread.

With this I can perform rudimentary recursive execution of code at regular intervals with the use of Delay followed by ContinueWith:

static void Main(string[] args)
{
    CancellationTokenSource cancellationToken = new CancellationTokenSource();

    Task.Delay(10000, cancellationToken.Token)
        .ContinueWith(x => DoStuff(10000, cancellationToken.Token),
            cancellationToken.Token);
}

private static void DoStuff(int timer, CancellationToken token)
{
    File.ReadAllText(@"C:\Users\somelogin\Desktop\test.txt");

    Task.Delay(timer, token)
        .ContinueWith(x => DoStuff(timer, token), token)
}

The DoStuff method calls itself via ContinueWith call until the token is used to cancel the attempt. What was problematic with this code is that if the antecedent (“a thing or event that existed before or logically precedes another”) get an exception, say the test.txt file does not exist, then you never get the opportunity to create a new asynchronous task. An exception closing the whole system down may not be what you want to happen. The simple way to overcome that is to place a try catch around the ReadAllText method, however, the framework has a solution for that also:

private static void DoStuff(int timer, CancellationToken token)
{
    File.ReadAllText(@"C:\Users\somelogin\Desktop\test.txt");

    Task.Delay(timer, token)
        .ContinueWith(x => DoStuff(timer, token), token)
        .ContinueWith(x => x.Exception.Handle(ex =>
        {
            DoStuff(timer, token);
            return true;
        }), TaskContinuationOptions.OnlyOnFaulted);
}

In the above example I created an additional ContinueWith but this one is designed to be called when an exception occurs in the antecedent (using TaskContinuationOptions.OnlyOnFaulted), it then gives you the option to still recursively call the DoStuff method.

This whole TAP pattern is really well thought out in my humble opinion.