Introduction
C# 6.0 has introduced no big concepts but many small features that make you keep cleaning your code, get rid of boilerplate, and let you stand up more clearly.
Getter-Only auto-properties
In the previous version of C#, auto-implemented properties must have “setters”, but this condition puts you in disadvantage because if you want to create auto-implemented properties, then you have to use both “getter” and “setter” along in your property. In C# 6.0, a new way of creating properties has arrived, i.e., we called it “Auto-Implemented Ready only properties” and these can be assigning in the constructor which will give you more benefits and reduce your coding.
Example
- publicint YourPropertyName { get; }
Initializer for auto-properties
We can also initialize auto-implemented property's default value directly, however, this makes senses. Suppose we have created an “Integer” type auto-implemented properties, then the default value will be “=Zero” but in case of "string" datatype, the default value will be “null”; this is error-prone. So, to make it error free, you can directly assign a default value while creating “Auto-Implemented Properties” like the below-given code.
Example
- publicstring YourPropertyName { get; } = "Your Property Name";
Using Static Members
Using static members, we can directly call static function/method without using the class name. Now, this makes sense. In the previous versions of C#, if we wanted to use static methods, then we had to use the class name to call a static method; however, prefixing class name with a static method all time is not good practice. So in “Using Static Members”, only one modification is needed while importing a namespace, use “static” keyword along with “using” keyword and we are ready to use the static method of imported namespace anywhere within the file. No need to call a static method in a traditional way.
Example
- using staticMath;
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public double dist {
- get {
- return Sqrt(X * X + Y + Y);
- }
- }
- }
String Interpolation
String format is very useful and versatile “API” but is bulky and the business with placeholder numbers gets confusing. It is error-prone and not good for large amount of data displaying on the console window. It is better if the values of format occur in their places and that is what “String Interpolation” syntax is here for.
Example
Without “String Interpolation”,
- using staticMath;
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public override string ToString() {
- returnFormat("({0},{1})", X, Y);
- }
- }
Example
Here, we can see that the values have occurred in their places.
with “String Interpolation”,
- using staticMath;
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public override string ToString() {
- return return $ "({X},{Y})";
- }
- }
Expression Bodies Methods.
There are many methods like this with a body and single return statements for “Lamda Expression”
Using “Lamda Expression”
- publicoverride string ToString() => $"({X},{Y})";
We can do the same with properties by avoiding the two levels of curly braces using
- publicdouble Dist => Sqrt(X*X+Y*Y);
Let’s pause to appreciate how simple and understandable this method got to be. See the below example.
- using staticMath;
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public double Dist => Sqrt(X * X + Y * Y);
- public override string ToString() => $ "({X},{Y})";
- }
Now, the above code is more simplified, readable, reliable, error free, and maintainable, however, that’s what Microsoft people are trying to give the flexibility that we can code in C-Sharp.
There are still a few more features to go.
Index Initializers.
Take an example of turning your class properties into “Json-Object”.
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
-
- public JObject toJson() {
- var result = new JObject();
- result["x"] = X;
- result["y"] = Y;
- return result;
- }
- }
In the above-mentioned code, we can initialize properties in object initializer but indexes have to be assigned in separate statements. Now we are extending object initializer to let you assign indices inside them with squire brackets syntax. Take an example of “ToJson()” Method below.
-
- publicJObject toJson() {
- var result = new JObject() {
- ["x"] = X, ["Y"] = Y
- };
- return result;
- }
Now, we can simplify it more and we don’t need temporary variable anymore.
-
- publicJObject toJson() {
- return new JObject() {
- ["x"] = X, ["Y"] = Y
- };
- }
In fact, we can turn the whole body into a single expression like below.
-
- publicJObject toJson()=> new JObject() { ["x"] = X, ["Y"] = Y };
Null Conditional Operator
Let’s look at the method turn “Json” object back to point objects. We are checking “null” object and object indexers “Nullable” types. We are checking “Json” itself is not null then by its members, are they null or not then we’ll finally convert to their inter-related datatypes and store it into respective properties. Let’s have a look in example written below.
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public static Point FromJson(JObject json) {
- if (json != null && json["x"] != null && json["x"].Type == JTokenType.Integer && json["y"] != null && json["y"].Type == JTokenType.Integer) {
- return new Point((int) json["x"], (int) json["y"]);
- }
- return null;
- }
- }
We are checking here null explicitly over and over again. Consider if you have a big object with more than 50 properties then this kinda null checking leads you in error prone zone.
Let’s have an example below which avoid explicit null checking system. Instead of old one, here we are using “?.” operator. We call it “Question dot Operator”. Now, this makes sense, here, explicit null checking converted into implicit null checking and it also reduces your code.
Example
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public static Point FromJson(JObject json) {
- if (json != null && json["x"] ? .Type == JTokenType.Integer && json["y"] ? .Type == JTokenType.Integer) {
- return new Point((int) json["x"], (int) json["y"]);
- }
- return null;
- }
- }
If null, then null - if not, then dot. (This is the rule of above system). Sometimes this “Question dot Operator”, people refer it if-else but we can improve our code by assigning “?” mark just after the “json” Object like this “json
?”. This means, first it will check null for the object then goes to its members and rest fades into the background. We can use this example more efficient way and also can reduce the codes.
See the below example.
- publicclass Point {
- public int X {
- get;
- } = 0;
- public int Y {
- get;
- } = 0;
- public Point(int x, int y) {
- X = x;
- Y = y;
- }
- public static Point FromJson(JObject json) {
- if (json ? ["x"] ? .Type == JTokenType.Integer && json ? ["y"] ? .Type == JTokenType.Integer) {
- return new Point((int) json["x"], (int) json["y"]);
- }
- return null;
- }
- }
We can see a great use of “Null-Conditioning Operator” call it “Dot” operator when you people triggering an event like below.
Suppose you have triggered an event like this and except this delegate may be null for some reason and we have to check for that first, see below example.
- varonChanged = OnChanged;
- If(onChanged != null) {
- onChanged(this, args);
- }
Now, the above mentioned checking is not “Thread safe”, someone might unsubscribe the last event handler just after you checked. This way really got unusual. With the null propagating operator, this is very simple to handle null checking.
- OnChanged?.Invoke(this, args);
This is not a problem anymore you can conditionally call delegate “Invoke” method and fact is delegate call only if it is not null.
The name of Operator
In this, you want to capture the string name (same as method name) of a method. You can achieve it using “nameof”. it helps to keep code valid when renaming of your program element or method name.
Example
Without using "nameof".
- publicPoint Add(Point point) {
- if (point == null) {
- throw new ArgumentNullException("Point");
- }
- }
Problem with this, when you refactoring your method, so you forget to change the string name (method name in mentioned “ArgumentNullException”) which is now out of sync and it is also not providing compile time checking instead better to use "nameof". You can think, “typeof” operator as we use to take up a type in method or collection same as you can use “nameof” for taking up method or type name. Let’s see example below.
- publicPoint Add(Point point) {
- if (point == null) {
- throw new ArgumentNullException(nameof(point));
- }
- }
If you start remaining your method then it also implies on “nameof” operator, otherwise it will give compile time error.
Exception Filters
We can use exception filters to filter the type of exception while designing our method if we know for sure this will give an exception we can name it and depending upon name we can give the error message and we can run multiple catch blocks to catch type of different exception. Here is an example of mine see.
Now here is my class along with method “add” where I have named exception (ArgumentNullException) as “point”, when an exception occurs, it will jump to the respective catch block where I have already been checking type of exception by proving name of exception which I have mentioned in our method body section. So when the name matches to this exception name, then this will display error on the console window.
- publicclass Point {
- public static Point Add(Point point) {
- try {
- if (point == null) {
- throw new ArgumentNullException(nameof(point));
- }
- } catch (ArgumentNullException ex) when(ex.ParamName == nameof(point)) {
- WriteLine($ "{ex.ParamName} for null exception. you have passed a null value in this function.");
- }
- return point;
- }
- }
And here is main method to run the above add function,
- classProgram {
- static void Main(string[] args) {
- Add(null);
- ReadKey();
- }
- }
Conclusion
Now, I’m concluding here with a thank you! I have explained all the common features which Microsoft has introduced in C# 6.O in Visual Studio 2015. Hope you people like this article.