Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Function-A Calling Another Function-B After A Returns

0.00/5 (No votes)
16 May 2014 1  
An introduction to async functions introduced in C# 2012/2013

Introduction

Let’s say there are two functions, Foo1 and Foo2. Foo2 needs to be called after Foo1, and only Foo1 can call Foo2:

A realistic scenario might be when Foo1 is invoked using a web service. Foo1 is called and needs to return as quickly as possible so that the calling client doesn’t hang. This means both Foo1 and Foo2 must be asynchronous functions, and that Foo2 must run after Foo1 has returned.

For Foo1 to be able to call Foo2 after Foo1 returns can be done in multiple ways. One way might be to have external queue into which tasks can be inserted so that they can be run when a certain state is set by a separate thread. This is good for scalable enterprise architecture, but seems a bit of an overkill when all we want to do is to call Foo2—after Foo1.

Another way is using the timer object. A third way is using the relatively new ‘async’ method modifier.

The “async” function modifier was introduced in Visual Studio 2012/2013.

Before talking more about the async modifier, here is a complete listing of the code that is also attached to this tip. It's a console application:

using System;

namespace MyCSasync
{
    using System.Threading;
    using System.Threading.Tasks;

    class MyClass
    {
        public static string[] Strings = new string[3];
        public static int Count = 0;

        private async Task Foo2()
        {
            await Task.Yield();

            Strings[Count++] = "Foo2 called at " + DateTime.Now.Ticks;
        }

        public async Task Foo1()
        {
            Strings[Count++] = "Foo1 at " + DateTime.Now.Ticks;

            // Call Foo2 asynchronously AND after this function returns.
            Foo2();

            Strings[Count++] = "End of Foo1 at " + DateTime.Now.Ticks;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass myclass = new MyClass();

            myclass.Foo1();

            while (MyClass.Count != 3) Thread.Sleep(1);
            foreach (string msg in MyClass.Strings)
            {
                Console.WriteLine(msg);
            }
        }
    }
} 

While Foo1() is called asynchronously from the Main function, it could be called from a web service method which needs to return back to a client as quickly as possible so the client doesn't seem to hang. Foo2() is a private function that will need to be called after Foo1 completes.

Foo2 is partially executed so that Foo1 can return. This partial execution is just

    await Task.Yield() 

This allows Foo2 to temporarily exit so that Foo1 can finish. The "Yield" method, as described by Microsoft, "creates an awaitable task that asynchronously yields back to the current context when awaited." That's exactly what we would like to do. There are other ways to do this. Using a delay. The problem with that approach is the behavior of the code may change depending on how fast your computer is. This is easy to test. If you use Task.Delay(1), which is 1 millisecond, it is more than enough to make the code above seem to be behaving the same. If you change the Delay parameter to a TimeSpan object with 1 tick, you may see that the code no longer works as expected.

When you run the code above (ctrl-F5), you should see something similar to:

Foo2 is called after Foo1. Note the tick difference, about 20,000. On my machine, that's about 3200th of a second. So a delay of 1 second would seem to work, but certainly not 1 tick. As an exercise, change the code "await Task.Yield()" to "await Task.Delay(1)" and you'll likely see that Foo2 is called after Foo1. Now change it to "await Task.Delay(TimeSpan.FromTicks(1))". You will see that Foo2 is called before "End of Foo1". This is because Foo2's await took less time than Foo1 could return.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here