As discussed in my last article on C# 6.0 features we have discussed some of the interesting features like : Auto property initialization, Expression bodied functions, Static class uses and string interpolation method. In this post, we will take the discussion ahead with more language features introduced with the new language.
The features will be covered with basic introduction to internals are :
5. Null Conditional operators
6. Exception filters
7. nameof operator
8. Dictionary initializers
9. await in try / finally.
10. Parameterless constructor for struct
Feature 5 : Null conditional operators
Getting into NullReferenceException or "Object reference not set to instance of an object" is one of the most common exception that every developer must see while working with the langauge. It has been a common problem where developers need to give extra stress to check the null value before calling any member functions. Null for compiler is unknown, and hence if you call a method on null, it will point nowhere and hence throws NullReferenceException and exists the stack.
To handle nulls Microsoft had introduced few language constructs already like Null coalesce operator (??) or Conditional operators. But with the new feature introduced in C# 6.0, the language team has introduced another operator which checks for null.
Null Conditional operator is a new construct that gives away a shortcut to condition the null check before calling its members.
Here in the above two lines you can see how the complexity rises when there are multiple number of null checking on an expression. In the first statement the address is checked with null and when it has address, it will only then evaluate the zipcode. On the second statement, the person object is checked with null, then its address and then finally the zipcode is evaluated.
With null conditional operator the code would look like :
Here the code is reduced greatly even though the actual expression logic remains the same. The ? mark is used for null conditioning. Null conditional operators does not exists as well, it is the same representation as that of the previous conditional operators. If you try to look into reflector, you will see it like :
You can see the null conditional operators are replaced by the compiler with normal conditional statements.
Feature 6 : Exception Filters
Now after so many syntactic sugar introduced with latest version of C#, this is the only new feature that directly relates to IL (Intermediate Language). From the very inception, the exception filters were there in CLR but was not exposed to the C# language. With C# 6.0, the exception filters finally came into existence and finally as a C# developer you can make use of it.
In C# the exception block contains try/catch/finally with multiple catch blocks supported. Based on type of the exception that has been encountered during runtime, the runtime chooses the appropriate catch block to execute. Exception filters allows you to filter out the catch blocks to ensure which catch block can handle the exception. With exception filters in place, there could be multiple catch blocks with same type where the type determines which filter it will call first.
Let us take a look at the code :
Here the ArgumentException is thrown when CallMe is invoked. The Exception filters are specified using when keyword just like in VB.NET. So the execution is like, it will call LogException method, executes the code and see whether the return statement is true or false. If it is true, it executes the catch block and exit, or otherwise it move and call LogAgainException method.
The exception filter expects a boolean value, hence the call to LogException should be a method returning bool or otherwise we need a comparison operator to always evaluate the when statement to boolean. Exception filters allows the developer to run arbitary code between the exception and the catch block execution without interfering the original stack trace of the exception object.
I have already told you that exception filters is a CLR concept. The IL is laid out as :
This tells the compiler to execute try block from line no --- to line ----. It will then call filter line and then call the handler which executes some bunch of lines. Cool ? Yes.
One small addition that I would want to add, if an exception filter encounters an exception and is left unhandled, the compiler handles it for you and automatically skip the exception block and moves to the next catch block. For instance if LogException in the code above throws an exception, it will call LogAgainException without modifying the Stack for ex.
Feature 7 : nameof Operator
nameof is a new addition to operator list supported by C#. This new operator is nothing but a compiler trick, where the compiler determines the name of a Property, Function or an Extension method and writes it directly in compiled output. For instance,
Feature 8 : Dictionary initializers
Dictionary is one of the common array object which used often to send data between objects. Unlike arrays, Dictionaries form an array of KeyValuePair. In modern days, Dictionary is used interchangeably with arrays because of its flexibility of defining key value set.
Here you can see a list is used to store string data, where index giving you the reference to individual objects. If I write the same with dictionary, it will look like :
Even though the basics remain the same, the developers are increasingly inclined to use the later as it gives a flexibility to assign any index. You can define "Abhishek" to 10 and "Abhijit" to 20 without the limitation of fixed incremental index usage of dictionary.
As more and more people are going to Dictionary, language team thought about giving easier constructs to define Dictionary. Even though we can go without it, but it is a nice to have feature. In C# 6.0, you can define dictionary using the following syntax :
Or even if the key is declared as string, you can also use like:
This way it is very easier to declare and use dictionaries. The last two syntaxes were introduced in C# 6.0.
Now if you think of the actual implementation, there is nothing as such. If you try to sneak peek on the compiled code, you will be seeing the same code with object being initialized inside the constructor.
Here even though the new construct is used, the dictionary object is actually initialized in constructor itself. The code is re-written by the compiler.
Feature 9: Await in catch and finally
If you are not using async / await stuffs too often you might have already overlooked that you cannot specify await in catch or finally block before the latest version of C#. Microsoft has initially thought that it wont be possible to allow awaits in catch/finally because the compiler creates a state machine which slices each and every await statements into a sequence of calls which can pause and resume the function upon request. But as try/catch/finally are handled by CLR, allowing such thing will indicate every errors in the state machine is properly handled and also each of try/catch/finally would need their individual state machines each.
Based on the complexity, microsoft haven't provided the feature in previous version, but as everything is handled by the compiler itself, it is a very important feature to have as a programmers perspective hence in latest version of C# 6.0, the feature have been revised and await in catch/finally is allowed.
Hence you can successfully compile the code above where the await works during the catch execution.
If you try looking at the code in reflector it will look very ugly with so many of StateMachine declarations and so many of goto statements to properly navigate to lines inside the state machine on failure. It would be nice if you can look into it personally, but if there is any problem understanding the implementation, feel free to ask me in discussions.
But as a benefit, you get this feature ready.
Feature 10: Parameterless constructor for struct
If you are unaware, there was no parameterless constructors in struct. This is because of the fact that ValueTypes has a unique behavior where it will be automatically assigned a default memory when declared.
For instance,
Here int is a struct (System.Int32) and the value of x would be automatically 0. You can even declare array of a struct. For instance,
Now the Struct MyStruct will automatically get the default(MyStruct) in the array even though its not explicitly constructed. If you want to know more why struct does not support default constructor, feel free to read the article I posted.
In C# 6.0 the parameterless constructor is allowed. This is also a trick made by the compiler. It actually replaces the default constructor with the parameterless constructor passed in when the new operator is used to construct the object.
So if you say,
The .NET will call the parameterless constructor for you.
Conclusion
There are lot more things coming with the new framework, new concepts, technologies etc. which I will cover one after another. Here is everything that are coming with C# 6.0 which is expected soon.
The features will be covered with basic introduction to internals are :
5. Null Conditional operators
6. Exception filters
7. nameof operator
8. Dictionary initializers
9. await in try / finally.
10. Parameterless constructor for struct
Feature 5 : Null conditional operators
Getting into NullReferenceException or "Object reference not set to instance of an object" is one of the most common exception that every developer must see while working with the langauge. It has been a common problem where developers need to give extra stress to check the null value before calling any member functions. Null for compiler is unknown, and hence if you call a method on null, it will point nowhere and hence throws NullReferenceException and exists the stack.
To handle nulls Microsoft had introduced few language constructs already like Null coalesce operator (??) or Conditional operators. But with the new feature introduced in C# 6.0, the language team has introduced another operator which checks for null.
Null Conditional operator is a new construct that gives away a shortcut to condition the null check before calling its members.
string zipcode = (address == null? null : address.zipcode); string zipcode = (person == null? null : (person.address == null ? null : person.address.zipcode))
Here in the above two lines you can see how the complexity rises when there are multiple number of null checking on an expression. In the first statement the address is checked with null and when it has address, it will only then evaluate the zipcode. On the second statement, the person object is checked with null, then its address and then finally the zipcode is evaluated.
With null conditional operator the code would look like :
string zipcode = address?.zipcode; string zipcode = person?.address?.zipcode;
Here the code is reduced greatly even though the actual expression logic remains the same. The ? mark is used for null conditioning. Null conditional operators does not exists as well, it is the same representation as that of the previous conditional operators. If you try to look into reflector, you will see it like :
You can see the null conditional operators are replaced by the compiler with normal conditional statements.
Feature 6 : Exception Filters
Now after so many syntactic sugar introduced with latest version of C#, this is the only new feature that directly relates to IL (Intermediate Language). From the very inception, the exception filters were there in CLR but was not exposed to the C# language. With C# 6.0, the exception filters finally came into existence and finally as a C# developer you can make use of it.
In C# the exception block contains try/catch/finally with multiple catch blocks supported. Based on type of the exception that has been encountered during runtime, the runtime chooses the appropriate catch block to execute. Exception filters allows you to filter out the catch blocks to ensure which catch block can handle the exception. With exception filters in place, there could be multiple catch blocks with same type where the type determines which filter it will call first.
Let us take a look at the code :
public class ExceptionFilters { public static bool LogException(Exception ex) { //Log return false; } public static bool LogAgainException(Exception ex) { //Log return true; } public void CallMe() { try { throw new ArgumentException("Exception"); } catch (Exception ex) when (LogException(ex)) { //Keep exception stack intact } catch(Exception ex) when (LogAgainException(ex)) { // Calling the catch } } }
Here the ArgumentException is thrown when CallMe is invoked. The Exception filters are specified using when keyword just like in VB.NET. So the execution is like, it will call LogException method, executes the code and see whether the return statement is true or false. If it is true, it executes the catch block and exit, or otherwise it move and call LogAgainException method.
The exception filter expects a boolean value, hence the call to LogException should be a method returning bool or otherwise we need a comparison operator to always evaluate the when statement to boolean. Exception filters allows the developer to run arbitary code between the exception and the catch block execution without interfering the original stack trace of the exception object.
I have already told you that exception filters is a CLR concept. The IL is laid out as :
.try --- to --- filter --- handler --- to ---
This tells the compiler to execute try block from line no --- to line ----. It will then call filter line and then call the handler which executes some bunch of lines. Cool ? Yes.
One small addition that I would want to add, if an exception filter encounters an exception and is left unhandled, the compiler handles it for you and automatically skip the exception block and moves to the next catch block. For instance if LogException in the code above throws an exception, it will call LogAgainException without modifying the Stack for ex.
Feature 7 : nameof Operator
nameof is a new addition to operator list supported by C#. This new operator is nothing but a compiler trick, where the compiler determines the name of a Property, Function or an Extension method and writes it directly in compiled output. For instance,
string name1 = nameof(this.MyProp); // evaluates MyProp string name2 = nameof(DateTime.Now);//evaluates Now string name3 = nameof(Console.WriteLine); //evaluates WriteLine string name4 = nameof(new List<string>().FirstOrDefault); // Evaluates FirstOrDefault
string name5 = nameof(name4);//Evaluates name4
The nameof operator works on any type where the type has a name. In case you specify a variable, the nameof operator will evaluate to the name of the variable.Feature 8 : Dictionary initializers
Dictionary is one of the common array object which used often to send data between objects. Unlike arrays, Dictionaries form an array of KeyValuePair. In modern days, Dictionary is used interchangeably with arrays because of its flexibility of defining key value set.
var list = new List<string>(); list.Add("Abhishek"); list.Add("Abhijit"); //Access var first = list[0]; var second = list[1];
Here you can see a list is used to store string data, where index giving you the reference to individual objects. If I write the same with dictionary, it will look like :
var dict = new Dictionary<int,string>(); dict.Add(0, "Abhishek"); dict.Add(1, "Abhijit"); //Access var first = dict[0]; var second = dict[1];
Even though the basics remain the same, the developers are increasingly inclined to use the later as it gives a flexibility to assign any index. You can define "Abhishek" to 10 and "Abhijit" to 20 without the limitation of fixed incremental index usage of dictionary.
As more and more people are going to Dictionary, language team thought about giving easier constructs to define Dictionary. Even though we can go without it, but it is a nice to have feature. In C# 6.0, you can define dictionary using the following syntax :
var dict = new Dictionary<int,string> { [10] = "Abhishek", [20] = "Abhijit" }; //Access var first = dict[10]; var second = dict[20];
Or even if the key is declared as string, you can also use like:
var dict = new Dictionary<string,string> { ["first"] = "Abhishek", ["second"] = "Abhijit" }; //Access var first = dict["first"]; var second = dict["second"];
This way it is very easier to declare and use dictionaries. The last two syntaxes were introduced in C# 6.0.
Now if you think of the actual implementation, there is nothing as such. If you try to sneak peek on the compiled code, you will be seeing the same code with object being initialized inside the constructor.
Here even though the new construct is used, the dictionary object is actually initialized in constructor itself. The code is re-written by the compiler.
Feature 9: Await in catch and finally
If you are not using async / await stuffs too often you might have already overlooked that you cannot specify await in catch or finally block before the latest version of C#. Microsoft has initially thought that it wont be possible to allow awaits in catch/finally because the compiler creates a state machine which slices each and every await statements into a sequence of calls which can pause and resume the function upon request. But as try/catch/finally are handled by CLR, allowing such thing will indicate every errors in the state machine is properly handled and also each of try/catch/finally would need their individual state machines each.
Based on the complexity, microsoft haven't provided the feature in previous version, but as everything is handled by the compiler itself, it is a very important feature to have as a programmers perspective hence in latest version of C# 6.0, the feature have been revised and await in catch/finally is allowed.
public async Task<string> DownloadUrl(string url) { WebClient client = new WebClient(); client.BaseAddress = "www.abhisheksur.com"; try { return await client.DownloadStringTaskAsync(url); } catch { return await client.DownloadStringTaskAsync("mvp"); } finally { //Await is also allowed. } }
Hence you can successfully compile the code above where the await works during the catch execution.
If you try looking at the code in reflector it will look very ugly with so many of StateMachine declarations and so many of goto statements to properly navigate to lines inside the state machine on failure. It would be nice if you can look into it personally, but if there is any problem understanding the implementation, feel free to ask me in discussions.
But as a benefit, you get this feature ready.
Feature 10: Parameterless constructor for struct
If you are unaware, there was no parameterless constructors in struct. This is because of the fact that ValueTypes has a unique behavior where it will be automatically assigned a default memory when declared.
For instance,
int x;
Here int is a struct (System.Int32) and the value of x would be automatically 0. You can even declare array of a struct. For instance,
struct MyStruct { public int Property1{get;set;} public string Property2 {get; set;} } MyStruct[] array = new MyStruct[10];
Now the Struct MyStruct will automatically get the default(MyStruct) in the array even though its not explicitly constructed. If you want to know more why struct does not support default constructor, feel free to read the article I posted.
In C# 6.0 the parameterless constructor is allowed. This is also a trick made by the compiler. It actually replaces the default constructor with the parameterless constructor passed in when the new operator is used to construct the object.
So if you say,
MyStruct s = new MyStruct();
The .NET will call the parameterless constructor for you.
Conclusion
There are lot more things coming with the new framework, new concepts, technologies etc. which I will cover one after another. Here is everything that are coming with C# 6.0 which is expected soon.
No comments:
Post a Comment