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)

Ref returns and locals

Passing objects by reference in C# is nothing new. This is done using the ref keyword. In C# 7.0, however, you can now return objects by reference and store these objects in a local variable by reference.

Getting ready

It is important to understand the concept of the ref keyword. When you pass a ref parameter, you are working with the variable itself, not just the value of the variable. This means that, if the value is changed, the original place in memory is updated, not only the value which would be a copy of the parameter. This becomes clearer in the following example.

How to do it...

  1. Inside the Chapter1 class, create a new method called GetLargest(). The method is nothing special. It only gets the largest of two values and returns it to the calling code.
        public int GetLargest(int valueA, int valueB)
{
if (valueA > valueB)
return valueA;
else
return valueB;
}
  1. Create a second method with the same name. Only this time, add the ref keyword.
        public ref int GetLargest(ref int valueA, ref int valueB)
{
if (valueA > valueB)
return ref valueA;
else
return ref valueB;
}
  1. In the static void Main method, create an instance to the Chapter1 class and call the GetLargest() method. Increment the variable val and write the variable values to the console window.
        int a = 10;
int b = 20;
Chapter1 ch1 = new Chapter1();
int val = ch1.GetLargest(a, b);
val += 25;

WriteLine($"val = {val} a = {a} b = {b} ");
  1. Then, write the following code just after the previous calling code, but call the ref ch1.GetLargest() method. Increment the refVal variable and write the variable values to the console window.
        ref int refVal = ref ch1.GetLargest(ref a, ref b);
refVal += 25;

WriteLine($"refVal = {refVal} a = {a} b = {b} ");
  1. Run your console application and consider the output displayed.

How it works...

In the console window, you will see two very different results. Simply put, in the first line, the variable a is the variable a, the variable b is the variable b, and the variable val is the variable val.

In the second line, the variablea is the variable a, the variable b is the variable b, and the variable refVal is the variable b. This is the whole crux of the ref keyword. In the first GetLargest() method, we returned the largest value into the variable val. This value was 20. The variable val and the variable b had no relation to one another as they were allocated different spaces in memory.

In the second GetLargest() method, we returned the largest variable itself (which was b) into the variable refVal. The variable refVal therefore becomes an alias of the variable b because they both point to the same space allocated in memory. To illustrate this even more clearly, let us have a look at the memory addresses for the variables.

From the Project menu, go to the Properties of the current project. In the Build tab, check the option to Allow unsafe code and save the properties.

Add the following code to your console application:

unsafe
{
IntPtr a_var_memoryAddress = (IntPtr)(&a);
IntPtr b_var_memoryAddress = (IntPtr)(&b);
IntPtr val_var_memoryAddress = (IntPtr)(&val);

fixed (int* refVal_var = &refVal)
{
IntPtr refVal_var_memoryAddress = (IntPtr)(refVal_var);
WriteLine($"The memory address of a is {a_var_memoryAddress}");
WriteLine($"The memory address of b is {b_var_memoryAddress}");
WriteLine($"The memory address of val is {val_var_memoryAddress}");
WriteLine($"The memory address of refVal is
{refVal_var_memoryAddress}");
}
}
This code is not really related to the recipe on ref returns and locals, so I'm not even going to go into it in any detail. If you want to learn more about pointers in C#, start with the MSDN article on Pointer types (C# Programming Guide): https://msdn.microsoft.com/en-us/library/y31yhkeb.aspx.

Run your console application and take a look at the memory addresses listed:

You will notice straightaway that variable b and variable refVal have the same memory address of 11531252, while variable b and variable val have different memory addresses.

So now for the million dollar question: Why is this feature in C# 7.0 even useful? Well, simply put, it can improve performance. Many developers mention that it will be quite useful for game programmers, who can now pass these aliases around to reference large data structures. This means that they don't have to make a copy of a large array (for example) in order to work with it. Using ref, they can create an alias that points to the original memory location of the array and read or modify it directly. Thinking of it this way suddenly brings the usefulness of this C# 7.0 feature into perspective.

Will I ever use it? I don't really know. Perhaps not often but, as with local functions, this feature of C# 7.0 is really a great addition to the developer's toolkit. It solves some really tricky problems when you want to get away from copying around large structures in your code.