I have had a quick look at the new language features coming in C# 6, and wanted to share some of my thoughts on the new changes. I created the following really simple class in order to explore how your code may adapt and hopefully become more readable and maintainable.
public class Rectangle { public int Length { get; set; } public int Width { get; set; } public Rectangle(int length, int width) { Length = length; Width = width; } public int Area { get { return Length * Width; } } public double Hypotenuse { get { return Math.Sqrt((Length * Length) + (Width * Width)); } } public override string ToString() { return String.Format("Length:{0}, Width:{1}, Area:{2}, Hypotenuse:{3}", Length, Width, Area, Hypotenuse); } }
Static Using clause
Firstly is the introduction of a new using clause that references types in addition to namespaces, so in the following example I reference the System.Math namespace.
using static System.Math;
This has the effect of putting only the static members of the namespace directly into scope, I can remove the Math prefix from my Hypotenuse class above and call the square root method directly as follows:
public double Hypotenuse { get { return Sqrt((Length * Length) + (Width * Width)); } }
Auto-implemented properties
Auto-implemented properties were introduced in C# 3.0 and made property-declaration more concise (see Length and Width above), there became no need to create private properties, the compiler is tasked with creating a private anonymous field on your behalf. The one obvious limitation of auto-implemented properties was that you were unable to initialize them as read-only (remove the set). C# 6 allows you to modify the definition of Length and Width properties to be read only, the class can now be immutable and after the object is created it cannot be modified from outside the class (see below).
public int Length { get; } public int Width { get; } public Rectangle(int length, int width) { Length = length; Width = width; }
Additionally you can now initialize auto properties with a value directly, as in the following:
public int Length { get; } = 34; public int Width { get; } = 22;
Concise String Formatting and Methods
The change here is pretty straightforward a more direct way to represent the ubiquitous String.Format (the $ represents the interpolated string). I have changed the original ToString method such that all the variables are in line, and so you no longer have do zero based math in your head to figure out which variable represents what output in your error logs!
public override string ToString() { return $"(Length:{Length}, Width:{Width}, Area:{Area}, Hypotenuse:{Hypotenuse})"; }
This leads directly into Lambda inspired method formats, these are designed to help simplify how a single line methods get written, and in the case of the override method above, it could be interpreted like this:
public override string ToString() => $"(Length:{Length}, Width:{Width}, Area:{Area}, Hypotenuse:{Hypotenuse})";
Or your get property could be reworked as follows:
public int Area => Length * Width;
This just feels better on properties rather than methods, as my assumption always remains that a property, by its convention and nature, is generally very sparse. I do see the potential for this being horribly abused.
Null-Condition operators
As developers we do a lot of repeated actions, probably non more than null checks. We check the parent object, then maybe a child object (or two), then we select the property or member variable we use and we can end up with our checks being more verbose than the action we want to take. For example:-
public override string ToString(NameValueCollection macromap) { if (macromap != null && macromap["prop"] != null && macromap["prop"].Count() == 1) { return macromap["prop"]; } return null; }
Null-condition operators are about making your null checks fade into the background so that that the purpose of the method shines through more clearly, thus our sample code transforms and ? represents a check of the preceding objects null status, if it is null do not evaluate the rest of the objects properties:
public override string ToString(NameValueCollection macromap) { if (macromap?["prop"]?.Count() == 1) { return macromap["prop"]; } return null; }
I love this feature and its applications across every code base I have ever seen will be almost entirely positive.
Of course you do not have to implement any of these features, but it will help if you can at least read them. There are more features that I have not had the chance to look at yet so I may do a follow up (nameof operator, Exception filters, await in catch and finally blocks, etc). If you want to see more then please check out Roslyn on GitHub.
What do you think of the feature list thus far? Do you see any of these features making things worse for you?
I'm not really sold on the using static directives. There's never really been a time where I've thought to myself "Man, I really wish I didn't have to type 'Math.'". It seems like a step towards code that is actually less explicit and less readable. I often like to know that I'm calling a static utility class or some other function of that nature.
Also, I'm sure the exception filter will be helpful, but man can I see that being horribly abused and leading to some really terrible code.
Comments are closed.