31

I want to write a pattern Promise/Deffered. Perfect variant in end is:

MyObject().CallMethodReturningPromise()
   .done( result => {
       ...something doing;
   } )
   .fail( error => {
       ...error handle;
   } )
   .always( () => {
       ...some code;
   } )

I've found this implementation https://bitbucket.org/mattkotsenas/c-promises/overview and https://gist.github.com/cuppster/3612000. But how can I use it to solve my task???

jpaugh
  • 6,634
  • 4
  • 38
  • 90
Mike
  • 750
  • 2
  • 10
  • 14
  • Out of interest, is there a practical difference between the Futures pattern and Promises? – Gusdor Oct 01 '14 at 08:03
  • 1
    @Gusdor the terminology is blurry - these terms mean different things in different languages. – Benjamin Gruenbaum Oct 01 '14 at 08:03
  • 2
    As a side note promises are _not_ about `.done` `.fail` and `.always` - they're more about `.then` and `.catch` for error handling. See http://stackoverflow.com/questions/22539815/arent-promises-just-callbacks – Benjamin Gruenbaum Oct 01 '14 at 08:17
  • @BenjaminGruenbaum I was under the impression that `Future` was a universal term. Imagine my disappointment when c# called them Tasks. – Gusdor Oct 01 '14 at 08:43
  • 2
    If you can't use Task (because you are stuck in an older version of .Net) I have a C# promise implementation that you might like to try. https://github.com/Real-Serious-Games/C-Sharp-Promise. Also available on nuget: https://www.nuget.org/packages/RSG.Promise/ – Ashley Davis Jan 30 '15 at 06:14
  • @AshleyDavis Your promise library looks great. Does it also work with `async` and `await` natively? i.e. for operations that don't have a completed or done event, unlike `DownloadStringCompleted` for `WebClient`. – GFoley83 Sep 26 '15 at 10:10
  • Unfortunately we only use .Net 3.5, so I don't yet have any experience with async/await. Please jump into the github project and try it out, if it doesn't do what you want then we can work that out together. – Ashley Davis Sep 27 '15 at 10:27
  • 1
    @AshleyDavis Had a play with your library over the weekend, love it! Submitted a pull request with async/await example usage. – GFoley83 Sep 27 '15 at 19:51

3 Answers3

49

C# solves this with Tasks

Tasks solve the same problem as promises do in JavaScript - and you can use them similarly. However normally, you shouldn't.

There are several differences:

  • Tasks have cancellation built in.
  • Tasks aren't always started, and you can have tasks and start them later.
  • Promises perform assimilation, you can't have a Promise<Promise<T>> but you can have a task of a task in C# and might need to call .Unwrap on tasks.
  • There is one canonical implementation of tasks in the TPL (task parallelization library) that ships with C# but many implementations of promises in JavaScript.

Using Tasks

Here's how you'd use them with the async/await syntax - which will be added to JavaScript in ES7 and can be used in ES6 with yield in some libraries.

async Task Foo(){
    try{
        var res = await myObject.CallMethodReturningTaskOrAsyncMethod();
        doSomethingWithResponse(res);
    } catch(e){
         // handle errors, this will be called if the async task errors
    } finally {
        // this is your .always
    }
}

You can also use .ContinueWith which parallels to .then but it's very uncommon in C# and is generally frowned upon when await can be used. You can learn more about using async/await here.

Deffereds are mapped to TaskCompletionSource instances and Promises are Tasks in C#. Task.WhenAll is used where you'd use $.when or Promise.all.

Where you'd usually write:

a().then(function(res){
    return b(res, "foo");
}).then(function(res2){
    // do work on res2
});

You'd do the following in C#:

var res = await a();
var res2 = await b(res, "foo");
// do work on res2.
Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 2
    @Multix with try/catch, in async functions in C#, you can use regular try/catch and handle asynchronous errors. Using `async/await` is useful for letting you write asynchronous code in a synchronous way. It's a _really_ powerful abstraction and you'll really enjoy it coming from JavaScript. – Benjamin Gruenbaum Oct 01 '14 at 08:07
  • The [try/catch reference](http://msdn.microsoft.com/en-us/library/0yd65esw.aspx) contains examples using async as well as a short tutorial on how they recommend handling errors with it and best practices. – Benjamin Gruenbaum Oct 01 '14 at 08:09
  • @Multix any progress? Did you end up solving it with my answer? – Benjamin Gruenbaum Dec 15 '14 at 12:56
  • @ImBlueDaBaDee *Why* did you propose your edit? The edit comment should cover that. – jpaugh Jun 16 '17 at 20:22
28

Seems to me, this perfectly fit with tasks:

var deferred = Task
    .Factory
    .StartNew(() => /* produce some result (promise) */);

// done
deferred
    .ContinueWith(d => Console.WriteLine(d.Result), TaskContinuationOptions.OnlyOnRanToCompletion);

// fail
deferred
    .ContinueWith(d => Console.WriteLine(d.Exception), TaskContinuationOptions.OnlyOnFaulted);

// always
deferred
    .ContinueWith(d => Console.WriteLine("Do something"));
Dennis
  • 37,026
  • 10
  • 82
  • 150
  • 1
    is there a way to ensure that the continuation gets called on the same thread ? – zumalifeguard Jun 11 '16 at 00:09
  • @zumalifeguard: look at this answer - http://stackoverflow.com/a/14058118/580053. In short, you can't ensure this in general. Maybe you're trying to do something wrong - it is better to describe particular problem you want to solve this way. – Dennis Sep 28 '16 at 07:09
  • I need to run on the same thread because I want to access a resources from the UI thread. – zumalifeguard Sep 29 '16 at 16:04
0

you can use asynchronous with Task, async and await as follows: pay attention for handling asynchronous you do not need use try catch

 public async Task Method()
   {
     await Task.Run(() =>
            {
                //operations
                Application.Current.Dispatcher.Invoke(() =>
                {
                    //grab the UI Dispatcher if you need
                });
            }).ContinueWith(task =>
            {
                if (task.IsCompleted)
                {
                    //operations success
                }
                else if (task.IsFaulted)
                {
                    //operations failed
                }
            });
        }
GhostCat
  • 137,827
  • 25
  • 176
  • 248
pejman
  • 740
  • 7
  • 13