C# 7.0 Features — Continued.

Dipak Gawade
5 min readMay 25, 2020

This is 2nd part of ‘C# 7.0 Features — let’s explore’ article. You have missed the previous one, I would recommend reading that one first.

5. Passing method result as ‘ref’

Have you ever thought you can get function-result as ‘reference’?

Consider, you have an array of integer numbers. You want to replace a number from an array but without knowing the position of replacement. How can we do that without using the in-built method? To replace a number, I should know its position or you must tell me the address location of that element so that I can change the value at that address location. If you are thinking of a solution that I shared in the last statement, the ‘ref’ keyword will come to your rescue.

We already have used ‘ref’ many times while passing and accepting method arguments. That’s why I need not explain the use of the ‘ref’ keyword in the argument handling. But to explain the usage in a statement, I would say ‘ref’ is passing the argument memory address, instead of the argument value. This gives you more power in the argument handling.

The same principle is used in handling method result as ‘reference’. If I get the result as address location of the number I want to replace, I can write the new number at that memory location and I need not update any data structure accessing that memory location.

What you have to do is, similar to argument passing to a method, add the ‘ref’ keyword at locations which are related to the ‘return’ of the method result i.e. ‘method signature’, the ‘return’ statement, and the code that is calling the method. Once you received the result from the method, you have ‘address’ of the returned value. You have more power with the modification of the returned result. in the example above, I modified the memory location with the new value.

Please note that there are some rules for the usage of the ‘ref’ keyword like this — the memory location you are sharing with others should be from global variable i.e. global array of integers. You cannot expect the local arrays to be modified by the outsider world. Secondly, this functionality is available to limited data structures e.g. Arrays. For data structures like lists and dictionaries, you cannot use the ‘ref’ functionality.

6. Generalized async return type

When Tasks were introduced as a feature in C#, people were excited as it promised better debug support and better readability than threads. It kept the promise. Tasks are widely popular now and they are used in many critical operations. When the result is expected to be returned from the task method, it is wrapped in task instance. In the following program, the returned result casts in Task instance.

However, this is boxing on value-type into object-type. In performance tight requirement, we would like to get rid of this boxing-unboxing operation to save extra ticks. C# 7.0 has provided a solution for this problem, cast results into value-type.

However, we need a Nuget package to opt for this feature.

Now, you can use the value type as following-

When you know the returned result is ‘value-type’, use ValueTask<> instead of Task<>

But the question is, how ValueTask<> has saved the day? Isn’t this another boxing-unboxing operation? To get the answer, check out the definitions of both — Task and ValueTask.

You will find that ValueTask is ‘structure’ and Task<> is class and this is your answer.

7. Local methods

My method should do two tasks — check if passed Id is present in already existing records. If not, return. Otherwise, update the database record with exception handling. These are basically two tasks — also there is no other method that would need to update the record in the database. It would be good if we call a method performing the real operation of the database handling only if the previous condition satisfies. This can be written as follows-

This way of writing inner methods would come handy if you are working with iterators or task-based operations.

In case of iterators — instead of passing iterator, you can pass the yielded values through the inner method (the inner method will pass through iterator collection and pass result one by one using yield.)

For task-based code, we can add multiple methods handling one task by breaking down a bigger task. In that case, when an exception occurs, we would know exactly which task has a problem.

8. Additional Expression-bodied members

C# 6.0 has introduced an amazing feature of expression-bodied member functions. C# 7.0 has extended that functionality to constructors, finalizers, and property getter-setters. One-liner codes without braces are still readable and save some lines.

9. Numerical literal Syntaxes are improved

One of the major problems to date with the readability of code was difficulty in reading large numbers. Human minds are trained to understand numbers having separators easily. C# 7.0 has made that possible in written programs as well. You can write big numbers in chunks of small digits e.g. 7_00_00_000 instead of 70000000. This will come handy in comparisons and reviews.

The second major improvement in literal syntaxes was brought through the introduction of ‘0b’ format. We are familiar with the ‘0x’ Hexadecimal format. We have used it in many places for masking, enumerations, etc. However, the binary representation was missing before C# 7.0

In this version, you can write ‘int number = 0b0001_0101;’ and it will work as expected. So in masking logic, instead of computing which decimal number to use for masking, you can directly write the binary mask. This will help a lot in improving the readability of already complicated mask-based code.

--

--

Dipak Gawade

Software geek, blogger. Passionate about learning new concepts and share knowledge. Believe in 'lifetime understanding' than 'interview prep'.