Skip to content

Update What's new for C# 7 #1351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 42 additions & 42 deletions docs/csharp/csharp-7.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ description: Get an overview of the new features coming in the upcoming version
keywords: C#, .NET, .NET Core, Latest Features, What's New
author: BillWagner
ms.author: wiwagn

ms.date: 10/03/2016
ms.date: 12/21/2016
ms.topic: article
ms.prod: visual-studio-dev-15
ms.technology: devlang-csharp
Expand All @@ -21,8 +20,8 @@ C# 7 adds a number of new features to the C# language:
* [Pattern Matching](#pattern-matching)
* [`ref` locals and returns](#ref-locals-and-returns)
* [Local Functions](#local-functions)
<!-- Not available in Preview 5 * [More expression bodied members](#more-expression-bodied-members) -->
<!-- * [`throw` Expressions](#throw-expressions) -->
* [More expression bodied members](#more-expression-bodied-members)
* [`throw` Expressions](#throw-expressions)
* [Generalized async return types](#generalized-async-return-types)
* [Numeric literal syntax improvements](#numeric-literal-syntax-improvements)

Expand Down Expand Up @@ -52,11 +51,6 @@ typed local variable:

[!code-csharp[OutVarVariableDeclarations](../../samples/snippets/csharp/new-in-7/new-in-7/program.cs#02_OutVarVariableDeclarations "Implicitly typed Out variable")]

<!--
Add a sample at RC that shows how if statements
scope out variables.
-->

* The code is easier to read.
- You declare the out variable where you use it, not on another line above.
* No need to assign an initial value.
Expand Down Expand Up @@ -100,12 +94,12 @@ names to each of the members of the tuple:

The `namedLetters` tuple contains fields referred to as `Alpha` and
`Beta`. In a tuple assignment, you can also specify the names of the fields
on the right hand side of the assignment:
on the right-hand side of the assignment:

[!code-csharp[ImplicitNamedTuple](../../samples/snippets/csharp/new-in-7/new-in-7/program.cs#06_ImplicitNamedTuple "Implicitly named tuple")]

The language allows you to specify names for the fields on both the
left and right hand side of the assignment:
left and right-hand side of the assignment:

[!code-csharp[NamedTupleConflict](../../samples/snippets/csharp/new-in-7/new-in-7/program.cs#07_NamedTupleConflict "Named tuple conflict")]

Expand All @@ -121,7 +115,7 @@ defines the type returned. There is no need for creating a new type.

Creating a tuple is more efficient and more productive.
It is a simpler, lightweight syntax to define a data structure that carries
more than one value. The example method below returns the minimimum and maximum
more than one value. The example method below returns the minimum and maximum
values found in a sequence of integers:

[!code-csharp[TupleReturningMethod](../../samples/snippets/csharp/new-in-7/new-in-7/program.cs#08_TupleReturningMethod "Tuple returning method")]
Expand Down Expand Up @@ -295,7 +289,7 @@ this by using unsafe code and returning a pointer to an `int` in previous versio
Let's walk through a series of changes to demonstrate the ref local feature
and show how to create a method that returns a reference to internal storage.
Along the way, you'll learn the rules of the ref return and ref local feature that
protects you from accidentally mis-using it.
protects you from accidentally misusing it.

Start by modifying the `Find` method declaration so that it returns a `ref int`
instead of a tuple. Then, modify the return statement so it returns the value
Expand Down Expand Up @@ -332,7 +326,7 @@ The second `WriteLine` statement in the example above prints out the value `42`,
not `24`. The variable `valItem` is an `int`, not a `ref int`. The `var`
keyword enables the compiler to specify the type, but will not implicitly
add the `ref` modifier. Instead, the value referred to by the `ref return`
is *copied* to the variable on the left hand side of the assignment. The
is *copied* to the variable on the left-hand side of the assignment. The
variable is not a `ref` local.

In order to get the result you want, you need to add the `ref` modifier
Expand All @@ -347,7 +341,7 @@ modified. The local variable has been declared with the `ref` modifier,
and it will take a `ref` return. You must initialize a `ref` variable when
it is declared, you cannot split the declaration and the initialization.

The C# language has two other rules that protect you from mis-using
The C# language has two other rules that protect you from misusing
the `ref` locals and returns:

* You cannot assign a value to a `ref` variable.
Expand All @@ -374,7 +368,7 @@ outside of the context of the single calling location.
For those designs, *local functions* enable you to declare methods
inside the context of another method. This makes it easier for readers
of the class to see that the local method is only called from the context
in which is it declaraed.
in which is it declared.

There are two very common use cases for local functions: public iterator
methods and public async methods. Both types of methods generate
Expand Down Expand Up @@ -432,57 +426,63 @@ work begins:
> could also be accomplished using *lambda expressions*. Those
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another existing typos: minimimum (line 118), declaraed (line 377)
mis-use should have no hyphen (lines 292 and 350)
left hand and right hand should be hyphened (line 103, 108, 335)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

> interested can [read more about the differences](local-functions-vs-lambdas.md)

<!--
## More expression bodied members
Not available in Preview 5 yet.
-->

<!--
C# 6 introduced [expression bodied members](csharp-6.md#expression-bodied-function-members)
for member functions, and read-only properties. C# 7 expands the allowed
members that can be implemented as expressions. In C# 7, you can implement
*constructors*, *finalizers*, and `get` and `set` accessors on *properties*
and *indexers*. The following class shows examples of each:

[!code-csharp[ExpressionBodiedMembers](../../samples/snippets/csharp/new-in-7/new-in-7/expressionmembers.cs#36_ExpressionBodiedEverything "new expression bodied members")]

> [!NOTE]
> This example does not need a finalizer, but it is shown
> to demonstrate the syntax. You should not implement a
> finalizer in your class unless it is necessary to release
> unmanaged resources. You should also consider using the
> @System.Runtime.InteropServices.SafeHandle class instead
> of managing unmanaged resources directly.

These new locations for expression bodied members represent
an important milestone for the C# language: These features
were implemented by community members working on the open-source
[Roslyn](https://github.com/dotnet/Roslyn) project.

## Throw expressions

Not available in Preview 5
The decision that `throw` was a statement meant that there
were C# constructs where you could not use it. These
In C#, `throw` has always been a statement. Because `throw` is a statement,
not an expression, there were C# constructs where you could not use it. These
included conditional expressions, null coalescing expressions, and some lambda
expressions. The addition of expression bodied members adds more locations
where `throw` expressions would be useful. C# 7 removes introduces *throw expressions*.
where `throw` expressions would be useful. So that you can write any of these
constructs, C# 7 introduces *throw expressions*.

The syntax is the same as you've always used for `throw` statements. Now,
you can place them in new locations, such as an expression bodied member:
The syntax is the same as you've always used for `throw` statements. The only difference
is that now you can place them in new locations, such as in a conditional expression:

```csharp
// Not implemented exception
```

```csharp
// Implement using ? :
```
[!code-csharp[Throw_ExpressionExample](../../samples/snippets/csharp/new-in-7/new-in-7/throwexpressions.cs#37_Throw_ExpressionExample "conditional throw expressions")]

This features enables using throw expressions in initialization expressions:

```csharp
// new way
```
[!code-csharp[ThrowInInitialization](../../samples/snippets/csharp/new-in-7/new-in-7/throwexpressions.cs#38_ThrowInInitialization "conditional throw expressions")]

Previously, those initializations would need to be in a constructor, with the
throw statements in the body of the constructor:

```csharp
// old way with ctor
```

[!code-csharp[ThrowInConstructor](../../samples/snippets/csharp/new-in-7/new-in-7/throwexpressions.cs#39_ThrowInConstructor "throw statements")]

> [!NOTE]
> Both of the preceding constructs will cause exceptions to be thrown during
> the construction of an object. Those are often difficult to recover from.
> For that reason, designs that throw exceptions during construction are
> discouraged.

-->

## Generalized async return types

Returning a `Task` object from async methods can introduce
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

found an existing typo: peformance

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

peformance bottlenecks in certain paths. `Task` is a reference
performance bottlenecks in certain paths. `Task` is a reference
type, so using it means allocating an object. In cases where a
method declared with the `async` modifier returns a cached result, or
completes synchronously, the extra allocations can become a significant
Expand Down
28 changes: 28 additions & 0 deletions samples/snippets/csharp/new-in-7/new-in-7/expressionmembers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace new_in_7
{
public class ExpressionMembersExample
{
#region 36_ExpressionBodiedEverything
// Expresion Bodied Constructor
public ExpressionMembersExample(string label) => this.Label = label;

// Expression Bodied Finalizer
~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");

private string label;

// Expression bodied get / set accessors.
public string Label
{
get => label;
set => this.label = value ?? "Default label";
}
#endregion
}
}
2 changes: 2 additions & 0 deletions samples/snippets/csharp/new-in-7/new-in-7/new-in-7.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AsyncWork.cs" />
<Compile Include="expressionmembers.cs" />
<Compile Include="MathUtilities.cs" />
<Compile Include="Iterator.cs" />
<Compile Include="patternmatch.cs" />
<Compile Include="Point.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MatrixSearch.cs" />
<Compile Include="throwexpressions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
Expand Down
50 changes: 50 additions & 0 deletions samples/snippets/csharp/new-in-7/new-in-7/throwexpressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace new_in_7
{
public class ConfigResource
{

}

public class ApplicationnOptions
{
private string name;

#region 38_ThrowInInitialization
private ConfigResource loadedConfig = LoadConfigResourceOrDefault() ??
throw new InvalidOperationException("Could not load config");
#endregion

#region 39_ThrowInConstructor
public ApplicationnOptions()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BillWagner Typo: nn in Applicationn

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tverboon Thanks for spotting that. Since this PR had already been merged, I created a new PR to fix the issue: #1361

{
loadedConfig = LoadConfigResourceOrDefault();
if (loadedConfig == null)
throw new InvalidOperationException("Could not load config");

}
#endregion


private static ConfigResource LoadConfigResourceOrDefault()
{
return new ConfigResource();
}

#region 37_Throw_ExpressionExample
public string Name
{
get => name;
set => name = value ??
throw new ArgumentNullException(paramName: nameof(value), message: "New name must not be null");
}
#endregion


}
}