Book Image

C# 7 and .NET Core Cookbook - Second Edition

Book Image

C# 7 and .NET Core Cookbook - Second Edition

Overview of this book

C# has recently been open-sourced and C# 7 comes with a host of new features for building powerful, cross-platform applications. This book will be your solution to some common programming problems that you come across with C# and will also help you get started with .NET Core 1.1. Through a recipe-based approach, this book will help you overcome common programming challenges and get your applications ready to face the modern world. We start by running you through new features in C# 7, such as tuples, pattern matching, and so on, giving you hands-on experience with them. Moving forward, you will work with generics and the OOP features in C#. You will then move on to more advanced topics, such as reactive extensions, Regex, code analyzers, and asynchronous programming. This book will also cover new, cross-platform .NET Core 1.1 features and teach you how to utilize .NET Core on macOS. Then, we will explore microservices as well as serverless computing and how these benefit modern developers. Finally, you will learn what you can do with Visual Studio 2017 to put mobile application development across multiple platforms within the reach of any developer.
Table of Contents (17 chapters)

Generalized async return types

If you use async/await (if not, check it out) the following feature of C# 7.0 will come in really handy. The only supported return types used to be Task<T>, Task, and void. Even then, void was also only used with event handlers such as a button click. The challenge, however, was that a Task<T> was allocated in situations where the result of the async operation was available at the time of awaiting. But, what does this even mean? Well consider an async method that returns a Task<T> : and that value has a time to live of n amount of seconds. If the async method is called within the time to live period, why go to the trouble of allocating another Task<T> object? This is where the ValueTask<T> comes into play; it will allow other types to be defined so that you can return them from an async method. This, therefore, reduces the Task<T> allocations, which in turn will lead to performance gains.

Getting ready

Start off by creating a new WinForms application and performing the following steps:

  1. Add a button, label, timer, and textbox to the Windows form.
  1. We need to add the System.Threading.Tasks.Extensions package from NuGet to implement the ValueTask<T> struct. This process should be familiar to you if you completed the Tuples recipe. Select the winform project and click on the Install button.
Note that I am using Visual Studio 2017 RC while writing this book. You probably will not need to add System.Threading.Tasks.Extensions from NuGet in the final release.
  1. A confirmation screen will be displayed to allow you to review the changes that are about to be made. Just click on OK. Accept the license agreement. Also make sure that you have added this using statement to your project.
        using System.Threading.Tasks;

We are now ready to write our code. The Windows app will call an async Task<T> method if the time to live has passed. Once it does that, the method will read a value and cache it. This cached value will be valid for 10 seconds (which is the time to live). If the method is run within the time to live period, then the cached value will be used and returned to the form. If the time to live has passed, the process repeats and the Task<T> method is called. The implementation will become clearer when you review the following code samples.

How to do it...

  1. Start by adding the following variables to your form.
        double timerTtl = 10.0D;
private DateTime timeToLive;
private int cacheValue;
  1. In the form load event, set the label with the timer text.
Strictly speaking, this is all just fluff. It's not really necessary when it comes to illustrating generalized async return types, but it helps us to visualize and understand the concept.
        private void Form1_Load(object sender, EventArgs e)
{
lblTimer.Text = $"Timer TTL {timerTtl} sec (Stopped)";
}
  1. Set the timer interval on the designer to 1000 ms and add the following code to the timer1_Tick event.
        private void timer1_Tick(object sender, EventArgs e)
{
if (timerTtl == 0)
{
timerTtl = 5;
}
else
{
timerTtl -= 1;
}
lblTimer.Text = $"Timer TTL {timerTtl} sec (Running)";
}
  1. Now create a method that simulates some sort of longer running task. Delay this for a second. Use the Random keyword to generate a random number and assign it to the cacheValue variable. Set the time to live, start the timer, and return the cached value to the calling code.
        public async Task<int> GetValue()
{
await Task.Delay(1000);

Random r = new Random();
cacheValue = r.Next();
timeToLive = DateTime.Now.AddSeconds(timerTtl);
timer1.Start();
return cacheValue;
}
  1. In the calling code, check to see if the time to live is still valid for the current cached value. If the time to live has expired, run the code that allocates and returns a Task<T> to get and set the cached value. If the time to live is still valid, just return the cached integer value.
You will notice that I am passing a Boolean out variable to indicate that a cached value has been read or set.
        public ValueTask<int> LoadReadCache(out bool blnCached)
{
if (timeToLive < DateTime.Now)
{
blnCached = false;
return new ValueTask<int>(GetValue());
}
else
{
blnCached = true;
return new ValueTask<int>(cacheValue);
}
}
  1. The code for the button click uses the out variable isCachedValue and sets the text in the textbox accordingly.
        private async void btnTestAsync_Click(object sender, EventArgs e)
{
int iVal = await LoadReadCache(out bool isCachedValue);
if (isCachedValue)
txtOutput.Text = $"Cached value {iVal} read";
else
txtOutput.Text = $"New value {iVal} read";
}
  1. When you finish adding all the code, run your application and click on the Test async button. This will read a new value from the GetValue() method, cache it, and start the time to live count down.
  1. If you click on the button again before the time to live has expired, the cached value is returned.
  1. When the time to live expires, clicking on the Test async button will call the GetValue() method again and the process repeats.

How it works...

ValueTask<T> is a very nice addition to C# 7.0. Microsoft, however, does suggest that you benchmark the performance of Task<T> versus ValueTask<T> when doing additional optimizing of your methods. A simple optimization however would be to simply replace the instances of Task<T> with ValueTask<T>.