Implementing JQuery style 'deferred' and 'promise' in C# I like the pattern of the jQuery Deferred object.

I like how you can call Resolve any number of times, but the listening objects will only be notified once. I also like how you can attach a listening object after Resolve has already been called, and the listening object will still get the notification. If you're programming in an uncertain multithreaded environment, it greatly reduces the amount of thinking you have to do.

I couldn't find an equivalent in the C# library, so here is my implementation (a basic subset so far):

using System;
using System.Collections.Concurrent;
using System.Threading;

interface IPromise
{
    void Done(Action action);
}

sealed class Deferred : IPromise
{
    readonly ConcurrentBag&lt;Action&gt; _actions = new ConcurrentBag&lt;Action&gt;();
    // using an int instead of a bool
    // so we can use Interlocked
    private int _isResolved = 0;

    internal void Resolve()
    {
        Interlocked.Exchange(ref _isResolved, 1);
        InvokeActions();
    }

    void IPromise.Done(Action action)
    {
        _actions.Add(action);
        if (_isResolved == 1)
        {
            InvokeActions();
        }
    }

    void InvokeActions()
    {
        Action action = null;
        while (_actions.TryTake(out action))
        {
            action();
        }
    }
}


For this code to be usable, it has to be completely 100% thread safe. Can anyone see a hole in it?

Also, am I just re-implementing something that already exists in some corner of the .NET base class library?

For the sake of context I'll provide a practical use: there's a long running application, and some code that must execute if a file exists. The file might exist when the code first runs, or might come to exist later, or might never exist at all.
I invoke it like this:

 string fullPath = GenerateWatchedFilePath();
 FileSystemWatcherUtils
      .WhenFileAppears(fullPath)
         .Done(() =&gt;
                {
                    using (var stream = File.OpenRead(fullPath))
                    {
                       // etc
                    }
                }
              );


And my implementation of WhenFileAppears:

public static IPromise WhenFileAppears(string fullPath)
{
   Deferred returnPromise = new Deferred();
   if (File.Exists(fullPath))
   {
      returnPromise.Resolve();
      return returnPromise;
   }
   string subFolder = Path.GetDirectoryName(fullPath);
   // This code assumes the subFolder exists
   // An exception will be thrown if it does not
   var fileSystemWatcher = new FileSystemWatcher(subFolder);
   int onceOnlyFlag = 0;
   Action disposeOfWatcherAndResolve = () =&gt;
   {
      if (Interlocked.Exchange(ref onceOnlyFlag, 1) == 0)
      {
          fileSystemWatcher.Dispose();
          returnPromise.Resolve();
      }
   };
   FileSystemEventHandler watcherHandler = (sender, args) =&gt;
     {
        if (args.FullPath == fullPath)
        {
           disposeOfWatcherAndResolve();
        }
     };
   fileSystemWatcher.Created += watcherHandler;
   fileSystemWatcher.Renamed += (sender, args) =&gt; watcherHandler(sender, args);
   fileSystemWatcher.EnableRaisingEvents = true;
   // Dealing with a race condition:
   // if the file came to exist between the last check
   // and the creation of the fileSystemWatcher
   if (File.Exists(fullPath))
   {
      disposeOfWatcherAndResolve();
   }
   return returnPromise;
}
I like how you can call Resolve any number of times, but the listening objects will only be notified once. I also like how you can attach a listening object after Resolve has already been called, and the listening object will still get the notification. If you're programming in an uncertain multithreaded environment, it greatly reduces the amount of thinking you have to do.


This sounds a lot like TaskCompletionSource along with the Task it controls.

Assuming you have a TaskCompletionSource&lt;T&gt; tcs:


To attach a listener, use tcs.Task.ContinueWith(_ =&gt; /* listener code here */). You can do this before or after the Task has been completed and the listener code will be executed only once after the Task has been completed.
To complete the Task (the equivalent of resolving), use tcs.TrySetResult(someValue). If you'll use the TrySetResult() variant instead of SetResult(), the second and following attempt at completing will be ignored (SetResult() would throw an exception).


The difference with your code is that TaskCompletionSource always has some result type. You can either just ignore that (using e.g. TaskCompletionSource&lt;object&gt; and SetResult(null)), or use the non-generic TaskCompletionSource from AsyncEx.