the little wonders of c# 6

44
The Little Wonders of C# 6 James Michael Hare Microsoft Visual C# MVP 4/27/2015 http://www.blackrabbitcoder.net / @BlkRabbitCoder

Upload: blackrabbitcoder

Post on 17-Jul-2015

3.823 views

Category:

Software


0 download

TRANSCRIPT

The Little Wonders of C# 6James Michael Hare

Microsoft Visual C# MVP4/27/2015

http://www.blackrabbitcoder.net/@BlkRabbitCoder

The CTP for VS2015 is available for download

Includes the CTP for C# 6

Several new language features

No earth-shaking changes

Still compatible with .NET 4.5

Syntactical sugar to help reduce boiler-plate code

Helps improve code readability and maintainability

Visual Studio 2015 is Upon Us!

The nameof() operator

Auto-property initialization

Indexed initializer lists

The using static directive

Method and property expressions

String interpolation

Enhanced exception filtering

The null conditional operator (?.)

New C# 6 Features

Sometimes we want the name of an identifier as a string

The nameof() Operator

We can hard-code, but if we rename the variable, we have to remember to update the string:

The nameof() Operator (cont)

Now, you can get a string representation of an identifier with nameof():

The nameof() Operator (cont)

Before, if you wanted to default an auto-property to a non-default value, there wasn’t a simple way.

Either:

Create a backing field with initializer, then wrap in property

Or create an auto-property and then assign a value in the constructor

This should really be a simple, one-step process.

Auto-Property Initialization

Now instead of this:

Auto-Property Initialization (cont)

Or this…:

Auto-Property Initialization (cont)

We can now do this!

Reduces several lines of boiler-plating.

Auto-Property Initialization (cont)

In addition, you can use it even if the property has no setter (i.e. a truly read-only property):

Auto-Property Initialization (cont)

Initializer lists now allow you to use indexers if the container supports them.

For example, you used to have to initialize a dictionary like this:

Indexed Initialization Lists

But now you can use the indexer syntax instead:

The syntax is much cleaner and clearly identifies which string is the key and which is the value.

Indexed Initialization Lists (cont)

Warning: just because a container supports indexing doesn’t mean initializing with it will always be logically sound…

For example:

What’s wrong with this?

Indexed Initialization Lists (cont)

It is legal and compiles with no errors.

However, you are attempting to set elements that are beyond the list size, which List<T> doesn’t allow.

This is the same as doing this:

Indexed Initialization Lists (cont)

So remember, it’s just syntactical sugar, it won’t stop you from performing a run-time illegal action.

To make that example work, you’d have to do something like:

Indexed Initialization Lists (cont)

There are many static methods where the enclosing class mainly acts as an organization point (e.g. Math).

Sometimes, these class names give context to the static member being called.

Other times, they become repetitive clutter.

The using static declaration allows you to import the static members of a type into your namespace.

Also allows you to limit extension methods imported.

The using static Directive

Consider the following:

A lot of these class names we can assume from context or are just organizational clutter.

The using static Directive (cont)

If our program is a console app, we can probably assume the Console.

Similarly, the Math and Enumerable classes don’t add much. We already know what Pow() and Range() do.

Now, we can import the static members of these types with using static:

The using static Directive (cont)

This would simplify our code to be:

We’ve removed a lot of redundant code without obscuring the clarity.

The using static Directive (cont)

It’s not just for classes, you can import the static members of structs or enums.

For example, doing this:

Would allow us to do this:

The using static Directive (cont)

Warning: just because you can do this doesn’t mean you always should.

Consider if you ran across this code:

There’s no context, so what the heck are we creating?

Here, the type would have given meaningful context:

The using static Directive (cont)

Sometimes, we have properties or methods that are so simple, the body is mostly boilerplate

Method and Property Expressions

You can now simplify with lambda expression syntax:

Handy for simple get-only properties, reduces the boilerplate around the get { } syntax.

Somewhat reduces syntax burden on methods.

Method and Property Expressions (cont)

Consider building a string in a single statement with multiple components.

Typically we either use concatenation:

Or string formatting:

String Interpolation

The problem with concatenation is that it breaks up the flow of the string you are building and makes it harder to envision the result.

Formatting helps solve this, but it removes the actual values from the string and makes it harder to visualize where the arguments will be placed.

In addition, if you specify the wrong indexes of placeholders you will get a runtime error.

String Interpolation (cont)

String interpolation fixes this, it allows us to use the actual values as the placeholders inside the string.

You simply use $ as a string prefix to signal the compiler to use interpolation, then enclose the values with curly brackets.

Behind the scenes, the compiler will generate the appropriate string format expression for you.

Gives you all the power of string formatting, with ability to visualize the values in the string itself.

String Interpolation (cont)

So now, our example becomes:

In addition, all string formatting options are available:

String Interpolation (cont)

.NET has long had exception filtering:

Enhanced Exception Filtering

Standard exception filtering is fine when you just care about the type of the exception thrown.

If you needed to make a decision to catch or not based on logic – instead of type -- it’s clunky.

For example, let’s assume we are dealing with a data layer that throws a dependency exception with an IsRetryable property.

You may want to catch and handle if the exception is retryable, but let it bubble up if not.

Enhanced Exception Filtering (cont)

Let’s assume our exception looks like this:

Enhanced Exception Filtering (cont)

To catch only retryable exceptions, we used to do this:

Enhanced Exception Filtering (cont)

Now, with C# 6, you can specify a logical filter as well:

Enhanced Exception Filtering (cont)

Now, you can have multiple catches on same type:

Enhanced Exception Filtering (cont)

Filtering conditions do not have to involve the exception, they can be any condition.

Filters are checked in order for the same type, this means that an unfiltered catch for a type must be after all filtered catches for that type.

Filter only evaluated if that exception type is thrown.

If exception does not meet the filter, it is notrethrown behind the scenes, it is simply not caught.

Enhanced Exception Filtering (cont)

Have you ever consumed a web method (or other API) with a deeply nested response?

To be safe you have to do several layers of null checks before getting to what you really want to check:

Null Conditional Operator

C# 6 adds a new null conditional operator (?.) to access a member if not null, or cascade if null.

This would make our logic:

In the above example, if response is null, or response.Results is null, the whole result will be null.

Null Conditional Operator (cont)

Note that all of these are legal, but different:

The first throws if response null but cascades if Results is null, the second cascades if response is nullbut throws if Results is null, the third cascades both.

Null Conditional Operator (cont)

A null-cascade that results in a value type will result in a nullable value type:

Though you can couple with the null-coallescingoperator (??) to provide a default if null.

Null Conditional Operator (cont)

The null conditional operator is not just for properties, you can use it for method calls as well.

Null Conditional Operator (cont)

Also simplifies raising events:

Null Conditional Operator (cont)

So what if you want to check for null before invoking an indexer on an array, List<T>, etc?

C# 6 has a syntax for null cascade on indexers (?[…]):

Null Conditional Operator (cont)

C# 6 adds a lot of syntactical sugary goodness.

Some of the features are more powerful than others, but all have power to help increase maintainability and readability of your code.

Like any tools, know when to use them and when you are overusing them.

Visual Studio 2015 is currently in CTP6, moving to RC.

Summary

Questions?