Introduction and Background
It has been a very long time, and trust me, I am fed up of “Cool new features of C# 6!” posts already. I mean, each post has the same things, same topics, same content and (usually!) the same code blocks to demonstrate the thing too. However, I never wanted to write the blog to describe new things in C#, but now I think I should explain the things that are done “under the hood” for C# 6’s code. I have been going through many posts and I already know what these new “cool” features are, so I just wanted to test them out and see when they work, how they work and when they are not going to work. Well definitely, that is something that people aren’t expecting by the C# architect team, however, let’s find them out. :-)
Also, it has already been very late for C# 6 to be discussed because C# 7 has already been into the discussions of the team, you may want to read more about what C# 7 team has on their list. C# 7 Work List of Features.
Anyways, none of them are the final versions, final statements, or “C# 7 must-haves”. They are just what they are trying to inject to C# as per the demand and ideas provided to them on GitHub and other networks that they are having.
Enough of C# 7 already, now you have already seen all of the features that were introduced in C# 6 and most of you have been using those features in your applications. But, did you try to use them in a way they were not intended to be used? I mean, have you tried to use them in a very “unknown” or “uncertain” manner?
Let me share what I think of those features. I would also love to hear what you think of them! :-)
Counting the Features of C# 6
Now let me show you a few things about these services in a way that you were not expecting or you never cared about! These features are definitely interesting, but, a few are useful in one way, and a few are not at all useful in one way. Depends on your project, your perspective and ideas. So let me start by the very famous (and my favorite C# 6) feature: String Interpolation.
String Interpolation
This feature is a great feature, personally saying, this is the best feature that I find on C# 6 features list. What I find easy while using “string interpolation” is, that I don’t have to use String.Format
, I don’t have to concatenate the string
s, I don’t have to use the StringBuilder
at all. What I can do is that I can just simply write the string
and it would include the variable data in the string
. Now let me show you an example of multiple methods that can be used.
private static string Name = "Afzaal Ahmad Zeeshan";
Console.WriteLine("Hello, my name is: " + Name);
Console.WriteLine(string.Format("Hello, my name is: {0}", Name));
StringBuilder builder = new StringBuilder();
builder.Append("Hello, my name is: ");
builder.Append(Name);
Console.WriteLine(builder.ToString());
Technically, their result is the same. They all say the same message, and how they do it, we can find that out using the Assembly language (or the MSIL code, if you are a fan of MSIL and not Assembly at the debug time), however, we do know that they present the same value on screen.
Figure 1: Same string rendered and generated, as a result of many ways.
Their IL benchmark would be different (because internally, they are three different ways). That is because, they themselves are different. Their IL generated would be like this:
IL_0000: nop
IL_0001: ldstr "Hello, my name is: "
IL_0006: ldsfld UserQuery.Name
IL_000B: call System.String.Concat
IL_0010: call System.Console.WriteLine
IL_0015: nop
IL_0016: ldstr "Hello, my name is: {0}"
IL_001B: ldsfld UserQuery.Name
IL_0020: call System.String.Format
IL_0025: call System.Console.WriteLine
IL_002A: nop
IL_002B: newobj System.Text.StringBuilder..ctor
IL_0030: stloc.0
IL_0031: ldloc.0
IL_0032: ldstr "Hello, my name is: "
IL_0037: callvirt System.Text.StringBuilder.Append
IL_003C: pop
IL_003D: ldloc.0
IL_003E: ldsfld UserQuery.Name
IL_0043: callvirt System.Text.StringBuilder.Append
IL_0048: pop
IL_0049: ldloc.0
IL_004A: callvirt System.Object.ToString
IL_004F: call System.Console.WriteLine
IL_0054: nop
IL_0055: ret
You can see, that (indirectly) they are all different and execute different functions. What happens, is a “syntactic sugar“. They are typically just functions that are executed and compiler allows you to write all of these simply.
Now coming to the new way of writing the string
s with variable content. C# 6 introduces this new way of writing the same message!
Console.WriteLine($"Hello, my name is: {Name}");
The output of this is also the same… But, how C# 6 does that is a bit of trick now. To find that part out, we will again go back and read the MSIL generated.
IL_0000: nop
IL_0001: ldstr "Hello, my name is: {0}"
IL_0006: ldsfld UserQuery.Name
IL_000B: call System.String.Format
IL_0010: call System.Console.WriteLine
IL_0015: nop
IL_0016: ret
Um, watching at this MSIL, what do you say? :-) If you pay attention to the highlighted code, this resembles the code that we wrote using the String.Format()
method. So what happens is that this is also a syntactic sugar. There is no addition of anything, it is just what the compiler does for you! Compiler simply takes away everything, and generates that previous version of code. Yet, in a very friendly and simple way. I like it.
Remarks and References
String
interpolation has been adopted by many programming languages by now. Swift by Apple and JavaScript (ECMAScript) is also moving forward to templated string
s. I personally feel, since string
type data is mostly used, this is a great feature. For more, please read:
- String class
- String.Format()
- String interpolation
Conditional try…catch
Now, I have never used VB.NET, because I was always busy in C# itself but I still hear that VB.NET had this feature way before C# implemented it. The conditional try
…catch
(or as the team calls them, “Exception filters“) just allows you to handle the exception when a condition is met, I am not going to talk about what they are, instead, I will talk about how you can use them in your code. So basically, if you execute a function that is supposed to have a side-effect, and before handling any further errors, you want to find out if there was a side-effect or did the error occur before the side-effect. You would possibly be left with only one way to check that out!
try {
} catch (MyException me) {
if(field.Updated()) {
}
} catch (Exception e) {
}
As an example of this case, have a look at the following code:
private int field = 25;
public static void Main(string[] args)
{
try {
Console.WriteLine("Do you want to change the field?");
if(Console.ReadLine() == "yes") { field = 34; }
throw new Exception();
} catch {
if(fieldModified()) {
}
}
}
public static bool fieldModified() {
return (field == 25) ? true : false;
}
This try catch
would allow us to check if our fields were modified, if not, then we can simply ignore as there were no side-effects.
Now what C# 6 allows you to do is to add a condition outside the block, so that you don’t even have to enter the block itself, and the condition would just check if it needs to go to this block, if not, then exception would continue to grow and later catch
blocks would try their luck, finally to the end. Something like this:
try {
Console.WriteLine("Do you want to change the field?");
if(Console.ReadLine() == "yes") { field = 34; }
throw new Exception();
} catch when (fieldModified()) {
}
So instead of writing that condition inside, we can write that condition in front of that catch
block itself. Technically, both were OK, only this way we are leaving most of the work to the compiler and we are designing the code to be more readable, read it like “try .. this code .. catch when field modified .. continue“. This provides you with a simple way of reading the code. The IL gets some branches around the catch
block so that code can jump from one location to another and so on.
Remarks and References
Technically, I won’t use this in any of my applications because I try to avoid transaction-like programming. But, if you are using a transaction-like programming, such as SQL queries, bank management systems, I would recommend that you use these conditions on your catch
es. They can be of great use when you are logging errors in transactions. The function used would determine if there were changes (or what-ever you want to do in that function!) and if that condition is true, error would be caught, logged (if code is provided) and then re-thrown (if code is provided).
For more:
- C# : How C# 6.0 Simplifies, Clarifies and Condenses Your Code
nameof Operator
Before saying at all, I want to confess that I have been one of those responders, who said, you cannot have the name of the variable! Compiler doesn’t know the name of the variables, they are just labels. Well, not anymore. C# 6 provides you with another “amazing” feature that lets you get the actual name of the variable, not just the value of that variable.
Before C# 6, nameof
operator was not present. With C# 6, this new feature can allow you to know the names of the variables, not just their values. So for example, previously we did:
Console.WriteLine($"Hello, my name is {Name}");
Now we can do this too:
Console.WriteLine($"Value of {nameof(Name)} variable is {Name}");
Figure 2: Use of nameof operator in real world.
However, the actual use cannot be determined here. The actual use of this would be when we want to know the variable names too. We could definitely (before C# 6) hardcode the names, but after modification, refactoring, they would be of no use anymore. However, now C# 6 can allow us to have the names of those variables too.
To understand the working, have a look at the MSIL generated:
IL_0000: nop
IL_0001: ldstr "Value of {0} variable is {1}"
IL_0006: ldstr "Name"
IL_000B: ldarg.0
IL_000C: ldfld UserQuery.Name
IL_0011: call System.String.Format
IL_0016: call System.Console.WriteLine
IL_001B: nop
IL_001C: ret
This shows that the variable names are passed as string
objects to the function and then the string
formatted (as we talked in the string
interpolation), and finally the result is printed. So basically, all of this is just sugar-coating.
Null-conditional Operator
For this feature too, I have always been very narrow-minded. I never liked it, perhaps because I have written a “good way to handle null
exception” as:
if(obj != null) {
}
try {
} catch (NullReferenceException e) {
}
But, things have changed. Previously, I was writing a library, in which I was supposed to get a list of objects from JSON data. So basically, if the source was empty or like “[]
”, the array would be typically null
. In other words, to overcome the exception, I would have to write something like this:
var list = JsonConvert.DeserializeObject<List<Type>>(jsonString);
return (list == null) ? new List<Type>() : list;
return list ?? new List<Type>();
However, as C# 6 introduced something new, just to overcome the null
exception in each line.
var item = list?[index];
I am still not very much pushed by this feature, because setting something to null
based on null
-ness of another is not a good idea. Is it? We can easily do this:
var list = Model.GetList();
var item = new Item();
if(list != null && index < list.Count) {
item = list[index];
} else {
}
var list = Model.GetList();
var item = list?[index];
if(item == null) {
}
Now basically, following this approach, we have “easily” removed on conditional block. But still, our code is exposed to:
- Null reference exception: We still need to check the item for this, or continue to use the same steps to avoid
null
reference exception along the track, and finally, tell the client, “Oooooops! There was a problem!”. - Index out of range: In the previous code, we would check the index too, however to do that, we would require a new block in C# 6 code, and that would ultimately lead us to a state where
null
-conditional operator would lose its meaning.
So, have a look at this code:
List<int> i = null;
var item = i?.First();
Technically, we know item is null
. But just to check it, we generate the MSIL too,
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: brtrue.s IL_0011
IL_0006: ldloca.s 02
IL_0008: initobj System.Nullable<System.Int32>
IL_000E: ldloc.2
IL_000F: br.s IL_001C
IL_0011: ldloc.0
IL_0012: call System.Linq.Enumerable.First
IL_0017: newobj System.Nullable<System.Int32>..ctor
IL_001C: stloc.1
IL_001D: ret
Look at IL_0017
, what this does is that it just creates a new instance of an integer of nullable type. So basically, what we have above is:
int? nullable = null;
The MSIL for this case is:
IL_0000: nop
IL_0001: ldloca.s 00
IL_0003: initobj System.Nullable<System.Int32>
IL_0009: ret
Gotcha! This is the same as to what we had previously. Only difference is the syntax now. Nothing new. So we can also conclude that our item
is of type “Nullable<int>
“. We already had that, didn’t we? :-)
Remarks and References
This is (yet!) another sugar coat to C# compiler and the syntax. But I like it. However, there are still many things that you may want to learn before digging any deeper into the code.
- Nullable Types in C#
Static, Just Got Better!
Another new feature provided by C# 6 is the static
keyword in the using
statement. So basically, what we have got is a method to include the classes themselves, and not just the namespace
packages. What this feature does is already very much popular, so let me just continue to talk about what I had to talk about. I have a few things that I want to talk about… Starting with the first one:
First of all, when you write something like:
using static System.Console;
It doesn’t mean that each time you call “WriteLine
” (or other Console
’s member functions), it would be the function of Console
that gets called. This is more like ambiguity here. For example, the following code:
using System;
using static System.Console;
namespace CSTest
{
class Program
{
static void Main(string[] args)
{
WriteLine("Love for all, hatred for none.");
Read();
}
public static void WriteLine(string message)
{
Console.WriteLine($"'{message}' printed by member function.");
}
}
}
The output of this program is:
Figure 3: Output of the member function.
So basically, what we can conclude is that even though our Console
class is introduced, but compiler prioritizes the member functions. The priority is done in the case of both being static. If your member function is instance, then compiler would raise an error, so in that case you will always have to write the full name for the function with the type it is associated to. Like this:
using System;
using static System.Console;7
namespace CSTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Love for all, hatred for none.");
Read();
}
public void WriteLine(string message)
{
Console.WriteLine($"'{message}' printed by member function.");
}
}
}
This would now run the function from Console
class object.
Figure 4: Message printed by Console.WriteLine function.
This just executes the function. There is another thing that I want to discuss, the static
include is not just for the built-in classes, you can use them in your cases and your class objects too. Just for the sake of example, I created a sample class that would allow us to use the functions in a similar behavior.
class Sample
{
public static void StaticFunction() { }
public void InstanceFunction() { }
}
struct SSample
{
public static void StructStaticFunction() { }
}
Now, I don’t want to demonstrate the use of struct
or class
. So, now you can call those functions in your own class as if you were calling them from within the class itself.
Remarks and References
This works for struct
s and as well as class
es. The thing is that this works with the functions who are:
Public
, private
functions are not shown (of course!) Static
, instance functions require an instance, so compiler doesn’t bother showing them at all.
Static
classes are all static
, their members are also meant to be static
so every member function of a static
class would be accessible. However, in case of instance classes, only static
functions are visible in the list of IntelliSense.
For more information, please read:
- Static Classes and Static Class Members
Auto-properties, and their Improvements
Auto-properties have been available in C# for a long time by now, the thing is that they now introduce a new feature. “Initializers” can be used to initialize these properties to their defaults. A few of the ways that they can be used is like this:
private string Name { get; set; } = "Afzaal Ahmad Zeeshan";
private string Name { get; } = "Afzaal Ahmad Zeeshan";
private readonly string Name = "Afzaal Ahmad Zeeshan";
But remember, the last one is a field, not a property. For example, see this:
private string Property { get; set; } = "Afzaal Ahmad Zeeshan";
private string getterOnlyProperty { get; } = "Afzaal Ahmad Zeeshan";
private readonly string readonlyField = "Afzaal Ahmad Zeeshan";
This would be translated as:
IL_0000: nop
IL_0001: ret
get_Property:
IL_0000: ldarg.0
IL_0001: ldfld UserQuery.<Property>k__BackingField
IL_0006: ret
set_Property:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery.<Property>k__BackingField
IL_0007: ret
get_getterOnlyProperty:
IL_0000: ldarg.0
IL_0001: ldfld UserQuery.<getterOnlyProperty>k__BackingField
IL_0006: ret
The code is categorized under getters and setters for the properties, and the readonly
field is just a variable in the program.
Remarks and References
The new thing introduced in C# 6 is that you can now set the values to a default, in previous versions, you would have to enter a new value in the constructor. However, now you can enter that value right there!
For more please read:
- Accessors in C# on MSDN.
Lambdas Have Evolved
If you have ever read my previous posts, you may have known that I am a huge fan of lambda expressions of C#, especially when it comes to handling the events. I have always enjoyed programming, based on these lambdas.
- Handling events in WPF in an easy and short hand way
What now can be done is that lambda expressions can be used now to create the functions too (just like before), not just that. They can be used to simplify the getter-only properties too.
The syntax cannot show you how simple it gets. For example, the following code block:
public int Multiply (int a, int b) { return a * b; }
It looks very much simple, and is optimized. However, the MSIL code looks “horrible”.
Multiply:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: mul
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
This is a very long MSIL, which would be translated and would require a lot of CPU cycles. While on the other hand, if you can see this code:
public int Multiply (int a, int b) => a * b;
This lambda expression does the same as what the previous one did. But it is very much performance-efficient. The MSIL generated with this code is like this:
Multiply:
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: mul
IL_0003: ret
How small MSIL code, right? So this demonstrates that using a lambda expression to write our function, we can not just simplify the code size, we can also fine-tune the code that is executed for that.
Another major use of these lambdas is while creating getter-only fields. Now, their topic is already discussed above. But, however, I would like to talk about them again…
public double PI { get; } = 3.14;
The MSIL generated for this would be (you guessed it right!) a get
property, and a backing up field. Like this:
get_PI:
IL_0000: ldarg.0
IL_0001: ldfld UserQuery.<PI>k__BackingField
IL_0006: ret
So basically, what we have is a block, that returns the value of the field that is backing up this property; whenever we call the property. Now, to fine tune it using C# 6, what we can do is something like this:
public double PI => 3.14;
The MSIL for this is really very amazing, just the way we improved the function, we can improve this field too, increasing the access time. So now the MSIL is:
get_PI:
IL_0000: ldc.r8 1F 85 EB 51 B8 1E 09 40
IL_0009: ret
Pretty much amazing, and short! It just pushes this content, as float
, on the stack. Then calls the return to provide the value. The thing is that we don’t need a backing field at all. To make it more readable, please read this:
public string PI => "Afzaal Ahmad Zeeshan";
Now, in the case of a field-backed-property, the value would be stored in the backing field and when we would call this, the backing field would be called (a new call!) and then that value would be returned. However, in this case, what happens is something like this:
get_PI:
IL_0000: ldstr "Afzaal Ahmad Zeeshan"
IL_0005: ret
Simply, this would load the string
on the stack, and would then return this value. It is more like having that constant field in your project that gets places wherever it is called from and so on.
Remarks and References
Lambda expressions are definitely very useful, not in just decreasing the syntax size, but also in making the source code size small, too. The lambdas are inherited from “Functional programming”, and well, in the world of object-oriented programming, they have seriously marked their place.
For more, please read:
- Functional programming
- Lambda expressions in C#
- => operator
Points of Interest
In this post, I have talked about the most “popular” and interesting features that C# 6 has introduced to its users. However, until now, most of the times I have only seen the “same song and dance“. Programmers have just talked about the fuss, no one talked about their internal implementation.
In this post, I have shown what difference they have, how they differ, who are just syntactic sugars and which really do have an influence on your programs. Basically, from this list, my favorites are:
- String interpolation
- Lambda expressions
Others are useful, yet I don’t feel like using them in my own projects. If you have anything else on your mind, that I yet don’t know… please share it with me. :-) I would love to hear.