From f33be5b9492fc78a472612909ee0464001500d5a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 11 Dec 2018 16:08:07 -0500 Subject: [PATCH 01/46] Step 1: Trim "What's New" article The "what's new" article has fewer examples, and provides an overview of the feature. --- docs/csharp/whats-new/csharp-6.md | 488 +++--------------------------- 1 file changed, 50 insertions(+), 438 deletions(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 6ff8652fb566f..e0ac881ab9431 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -1,80 +1,18 @@ --- title: What's New in C# 6 - C# Guide description: Learn the new features in C# Version 6 -ms.date: 09/22/2016 -ms.assetid: 4d879f69-f889-4d3f-a781-75194e143400 +ms.date: 12/12/2018 --- # What's New in C# 6 -The 6.0 release of C# contained many features that improve -productivity for developers. Features in this release include: - -* [Read-only auto-properties](#read-only-auto-properties): - - You can create read-only auto-properties that can be set only in constructors. -* [Auto-property initializers](#auto-property-initializers): - - You can write initialization expressions to set the initial value of an auto-property. -* [Expression-bodied function members](#expression-bodied-function-members): - - You can author one-line methods using lambda expressions. -* [using static](#using-static): - - You can import all the methods of a single class into the current namespace. -* [Null-conditional operators](#null-conditional-operators): - - You can concisely and safely access members of an object while still checking for null with the null conditional operator. -* [String interpolation](#string-interpolation): - - You can write string formatting expressions using inline expressions instead of positional arguments. -* [Exception filters](#exception-filters): - - You can catch expressions based on properties of the exception or other program state. -* [The `nameof` expression](#the-nameof-expression): - - You can let the compiler generate string representations of symbols. -* [await in catch and finally blocks](#await-in-catch-and-finally-blocks): - - You can use `await` expressions in locations that previously disallowed them. -* [Index initializers](#index-initializers): - - You can author initialization expressions for associative containers as well as sequence containers. -* [Extension methods for collection initializers](#extension-add-methods-in-collection-initializers): - - Collection initializers can rely on accessible extension methods, in addition to member methods. -* [Improved overload resolution](#improved-overload-resolution): - - Some constructs that previously generated ambiguous method calls now resolve correctly. -* [`deterministic` compiler option](#deterministic-compiler-output): - - The deterministic compiler option ensures that subsequent compilations of the same source generate the same binary output. - -The overall effect of these features is that you write more concise code -that is also more readable. The syntax contains less ceremony for many -common practices. It's easier to see the design intent with less -ceremony. Learn these features well, and you'll be more productive, -write more readable code, and concentrate more on your core features -than on the constructs of the language. - -The remainder of this topic provides details on each of these features. - -## Auto-property enhancements - -The syntax for automatically implemented properties (usually referred to as 'auto-properties') -made it very easy to create properties -that had simple get and set accessors: - -[!code-csharp[ClassicAutoProperty](../../../samples/snippets/csharp/new-in-6/oldcode.cs#ClassicAutoProperty)] - -However, this simple syntax limited the kinds of designs you could support using -auto-properties. C# 6 improves the auto-properties capabilities so that you can use -them in more scenarios. You won't need to fall back on the more verbose syntax of -declaring and manipulating the backing field by hand so often. - -The new syntax addresses scenarios for read-only properties, and for initializing -the variable storage behind an auto-property. - -### Read-only auto-properties - -*Read-only auto-properties* provide a more concise syntax to create -immutable types. The closest you could get to immutable types -in earlier versions of C# was to declare private setters: - -[!code-csharp[ClassicReadOnlyAutoProperty](../../../samples/snippets/csharp/new-in-6/oldcode.cs#ClassicReadOnlyAutoProperty)] - -Using this syntax, the compiler doesn't ensure that the type really is immutable. It only -enforces that the `FirstName` and `LastName` properties are not modified from any -code outside the class. - -Read-only auto-properties enable true read-only behavior. You declare the auto-property +The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive, write more readable code. You can concentrate more on your features than on the constructs of the language. + +The rest of this article provides an overview of each of these features, with a link to explore each feature. + +## Read-only auto-properties + +*Read-only auto-properties* provide a more concise syntax to create immutable types. You declare the auto-property with only a get accessor: [!code-csharp[ReadOnlyAutoProperty](../../../samples/snippets/csharp/new-in-6/newcode.cs#ReadOnlyAutoProperty)] @@ -98,483 +36,157 @@ public class Student } ``` -This feature enables true language support for creating immutable types and using -the more concise and convenient auto-property syntax. - -If adding this syntax does not remove an accessible method, it is a [binary compatible change](version-update-considerations.md#binary-compatible-changes). - -### Auto-property initializers +This feature enables true language support for creating immutable types and using the more concise and convenient auto-property syntax. -*Auto-property initializers* let you declare the initial value for -an auto-property as part of the property declaration. In earlier versions, -these properties would need to have setters and you would need -to use that setter to initialize the data storage used by the backing -field. Consider this class for a student that contains the name and a -list of the student's grades: +If adding this syntax doesn't remove an accessible method, it's a [binary compatible change](version-update-considerations.md#binary-compatible-changes). -[!code-csharp[Student](../../../samples/snippets/csharp/new-in-6/oldcode.cs#Student)] - -As this class grows, you may include other constructors. Each constructor -needs to initialize the Grades property, or you'll introduce errors. +## Auto-property initializers -C# 6 enables you to assign an initial value for the storage used by an -auto-property in the auto-property declaration: +*Auto-property initializers* let you declare the initial value for an auto-property as part of the property declaration. [!code-csharp[Initialization](../../../samples/snippets/csharp/new-in-6/newcode.cs#Initialization)] -The `Grades` member is initialized where it is declared. That makes it -easier to perform the initialization exactly once. The initialization -is part of the property declaration, making it easier to equate the -storage allocation with public interface for `Student` objects. - -Property Initializers can be used with read-only properties, as shown above, and with read/write properties as well, as shown here. - -[!code-csharp[ReadWriteInitialization](../../../samples/snippets/csharp/new-in-6/newcode.cs#ReadWriteInitialization)] +The `Grades` member is initialized where it's declared. That makes it easier to perform the initialization exactly once. The initialization is part of the property declaration, making it easier to equate the storage allocation with public interface for `Student` objects. ## Expression-bodied function members -The body of a lot of members that we write consist of only one statement -that can be represented as an expression. You can reduce that syntax by -writing an expression-bodied member instead. It works for methods and -read-only properties. For example, an override of `ToString()` is often -a great candidate: +Many members that you write are single statements that could be single expressions. Write an expression-bodied member instead. It works for methods and read-only properties. For example, an override of `ToString()` is often a great candidate: [!code-csharp[ToStringExpressionMember](../../../samples/snippets/csharp/new-in-6/newcode.cs#ToStringExpressionMember)] -You can also use expression-bodied members in read-only properties as well: +You can also use this syntax for read-only properties: [!code-csharp[FullNameExpressionMember](../../../samples/snippets/csharp/new-in-6/newcode.cs#FullNameExpressionMember)] Changing an existing member to an expression bodied member is a [binary compatible change](version-update-considerations.md#binary-compatible-changes). - ## using static -The *using static* enhancement enables you to import the static methods -of a single class. Previously, the `using` statement imported all types -in a namespace. - -Often we use a class' static methods throughout our code. Repeatedly -typing the class name can obscure the meaning of your code. A common -example is when you write classes that perform many numeric calculations. -Your code will be littered with , and other calls -to different methods in the class. The new `using static` syntax can make these -classes much cleaner to read. You specify the class you're using: +The *using static* enhancement enables you to import the static methods of a single class. You specify the class you're using: [!code-csharp[UsingStaticMath](../../../samples/snippets/csharp/new-in-6/newcode.cs#UsingStaticMath)] -And now, you can use any static method in the class without -qualifying the class. The class is a great use case for -this feature because it does not contain any -instance methods. You can also use `using static` to import a -class' static methods for a class that has both static -and instance methods. One of the most useful examples is : +The does not contain any instance methods. You can also use `using static` to import a class' static methods for a class that has both static and instance methods. One of the most useful examples is : [!code-csharp[UsingStatic](../../../samples/snippets/csharp/new-in-6/newcode.cs#UsingStatic)] > [!NOTE] -> You must use the fully qualified class name, `System.String` -> in a static using statement. -> You cannot use the `string` keyword instead. - -You can now call static methods defined in the class without -qualifying those methods as members of that class: +> You must use the fully qualified class name, `System.String` in a static using statement. You cannot use the `string` keyword instead. -[!code-csharp[UsingStaticString](../../../samples/snippets/csharp/new-in-6/newcode.cs#UsingStaticString)] - -The `static using` feature and extension methods interact in -interesting ways, and the language design included some rules -that specifically address those interactions. The goal is to -minimize any chances of breaking changes in existing codebases, -including yours. - -Extension methods are only in scope when called using the -extension method invocation syntax, not when called as a static method. -You'll often see this in LINQ queries. You can import the LINQ pattern -by importing . +When imported from a `static using` statement, extension methods are only in scope when called using the extension method invocation syntax. They aren't in scope when called as a static method. You'll often see this in LINQ queries. You can import the LINQ pattern by importing , or . [!code-csharp[UsingStaticLinq](../../../samples/snippets/csharp/new-in-6/newcode.cs#usingStaticLinq)] -This imports all the methods in the class. -However, the extension methods are only in scope when called as extension -methods. They are not in scope if they are called using the static method -syntax: - -[!code-csharp[UsingStaticLinqMethod](../../../samples/snippets/csharp/new-in-6/newcode.cs#UsingStaticLinkMethod)] +You typically call extension methods using extension method invocation expressions. Adding the class name in the rare case where you call them using static method call syntax resolves ambiguity. -This decision is because extension methods are typically called using -extension method invocation expressions. In the rare case where they are -called using the static method call syntax it is to resolve ambiguity. -Requiring the class name as part of the invocation seems wise. - -There's one last feature of `static using`. The `static using` directive -also imports any nested types. That enables you to reference any nested -types without qualification. +The `static using` directive also imports any nested types. You can reference any nested types without qualification. ## Null-conditional operators -Null values complicate code. You need to check every access -of variables to ensure you are not dereferencing `null`. The -*null conditional operator* makes those checks much easier -and fluid. - -Simply replace the member access `.` with `?.`: +The *null conditional operator* makes null checks much easier and fluid. Replace the member access `.` with `?.` and use expressions between `{` and `}` instead of ordinals: [!code-csharp[NullConditional](../../../samples/snippets/csharp/new-in-6/program.cs#NullConditional)] -In the preceding example, the variable `first` is assigned `null` if the person object -is `null`. Otherwise, it gets assigned the value of the `FirstName` property. Most importantly, -the `?.` means that this line of code does not generate a `NullReferenceException` when -the `person` variable is `null`. Instead, it short-circuits and produces `null`. +In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it gets assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` when the `person` variable is `null`. Instead, it short-circuits and produces `null`. -Also, note that this expression returns a `string`, regardless of the value of `person`. -In the case of short circuiting, the `null` value returned is typed to match the full -expression. +This expression returns a `string`, regardless of the value of `person`. When the expression short-circuits, the `null` value returned is typed to match the full expression. -You can often use this construct with the *null coalescing* operator to assign -default values when one of the properties are `null`: +You often use this construct with the *null coalescing* operator to assign default values when one of the properties is `null`: [!code-csharp[NullCoalescing](../../../samples/snippets/csharp/new-in-6/program.cs#NullCoalescing)] -The right hand side operand of the `?.` operator is not limited to properties or fields. -You can also use it to conditionally invoke methods. The most common use of member functions - with the null conditional operator is to safely invoke delegates -(or event handlers) that may be `null`. You'll do this by calling the delegate's `Invoke` method -using the `?.` operator to access the member. You can see an example in the -[delegate patterns](../delegates-patterns.md#handling-null-delegates) topic. +You can also use `?.` to conditionally invoke methods. The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be `null`. You'll call the delegate's `Invoke` method using the `?.` operator to access the member. You can see an example in the +[delegate patterns](../delegates-patterns.md#handling-null-delegates) article. -The rules of the `?.` operator ensure that the left-hand side of the operator is -evaluated only once. This is important and enables many idioms, including the -example using event handlers. Let's start with the event handler usage. In previous -versions of C#, you were encouraged to write code like this: - -```csharp -var handler = this.SomethingHappened; -if (handler != null) - handler(this, eventArgs); -``` - -This was preferred over a simpler syntax: - -```csharp -// Not recommended -if (this.SomethingHappened != null) - this.SomethingHappened(this, eventArgs); -``` - -> [!IMPORTANT] -> The preceding example introduces a race condition. The `SomethingHappened` -> event may have subscribers when checked against `null`, and those subscribers -> may have been removed before the event is raised. That would cause -> a to be thrown. - -In this second version, the `SomethingHappened` event handler might -be non-null when tested, but if other code removes a handler, -it could still be null when the event handler was called. - -The compiler generates code for the `?.` operator that ensures -the left side (`this.SomethingHappened`) of the `?.` expression is evaluated once, and the result -is cached: +The rules of the `?.` operator ensure that the left-hand side of the operator is evaluated only once. It enables many idioms, including the following example using event handlers: ```csharp // preferred in C# 6: this.SomethingHappened?.Invoke(this, eventArgs); ``` -Ensuring that the left side is evaluated only once also enables you -to use any expression, including method calls, on the left side of the -`?.` Even if these have side-effects, they are evaluated once, so the -side effects occur only once. You can see an example in our content -on [events](../events-overview.md#language-support-for-events). +Ensuring that the left side is evaluated only once also enables you to use any expression, including method calls, on the left side of the `?.` ## String interpolation -C# 6 contains new syntax for composing strings from a string -and embedded expressions that are evaluated to produce other string values. - -Traditionally, you needed to use positional parameters in a method -like : - -[!code-csharp[stringFormat](../../../samples/snippets/csharp/new-in-6/oldcode.cs#stringFormat)] - -With C# 6, the new [string interpolation](../language-reference/tokens/interpolated.md) feature enables you to embed -the expressions in a string. Simply preface the string with `$`: +With C# 6, the new [string interpolation](../language-reference/tokens/interpolated.md) feature enables you to embed the expressions in a string. Simply preface the string with `$`: [!code-csharp[stringInterpolation](../../../samples/snippets/csharp/new-in-6/newcode.cs#FullNameExpressionMember)] -This example uses property expressions for the substituted -expressions. You can expand on this syntax to use any expression. For -example, you could compute a student's grade point average as part of -the interpolation: - -[!code-csharp[stringInterpolationExpression](../../../samples/snippets/csharp/new-in-6/newcode.cs#stringInterpolationExpression)] - -Running the preceding example, you would find that the output for `Grades.Average()` -might have more decimal places than you would like. The string interpolation -syntax supports all the format strings available using earlier formatting -methods. You specify the format string inside the braces. Add a `:` following -the expression to format: +This example uses properties for the substituted expressions. You can use any expression. For example, you could compute a student's grade point average as part of the interpolation: [!code-csharp[stringInterpolationFormat](../../../samples/snippets/csharp/new-in-6/newcode.cs#stringInterpolationFormat)] -The preceding line of code formats the value for `Grades.Average()` as -a floating-point number with two decimal places. +The preceding line of code formats the value for `Grades.Average()` as a floating-point number with two decimal places. -The `:` is always interpreted as the separator between the expression -being formatted and the format string. This can introduce problems when -your expression uses a `:` in another way, such as a [conditional operator](../language-reference/operators/conditional-operator.md): - -```csharp -public string GetGradePointPercentages() => - $"Name: {LastName}, {FirstName}. G.P.A: {Grades.Any() ? Grades.Average() : double.NaN:F2}"; -``` - -In the preceding example, the `:` is parsed as the beginning of the format string, not part -of the conditional operator. In all cases where this happens, surround the expression with parentheses to force the compiler to interpret -the expression as you intend: - -[!code-csharp[stringInterpolationConditional](../../../samples/snippets/csharp/new-in-6/newcode.cs#stringInterpolationConditional)] - -There aren't any limitations on the expressions you can place between -the braces. You can execute a complex LINQ query inside an interpolated -string to perform computations and display the result: - -[!code-csharp[stringInterpolationLinq](../../../samples/snippets/csharp/new-in-6/newcode.cs#stringInterpolationLinq)] - -You can see from this sample that you can even nest a string interpolation -expression inside another string interpolation expression. This example -is very likely more complex than you would want in production code. -Rather, it is illustrative of the breadth of the feature. Any C# expression -can be placed between the curly braces of an interpolated string. - -To get started with string interpolation, check the [String interpolation in C#](../tutorials/intro-to-csharp/interpolated-strings.yml) interactive tutorial. - -### String interpolation and specific cultures - -All the examples shown in the preceding section format the strings using the current -culture on the machine where the code executes. Often you -may need to format the string produced using a specific culture. -To do that use the fact that the object produced by a string interpolation can be implicitly converted to . - -The instance contains the composite format string, and the results -of evaluating the expressions before converting them to strings. Use the method to specify the culture when -formatting a string. For example, the following example produces a string -using German culture. (It uses the ',' character -for the decimal separator, -and the '.' character as the thousands separator.) +Often you may need to format the string produced using a specific culture. You use the fact that the object produced by a string interpolation can be implicitly converted to . The instance contains the composite format string, and the results of evaluating the expressions before converting them to strings. Use the method to specify the culture when formatting a string. For example, the following example produces a string using German culture. (It uses the ',' character for the decimal separator, and the '.' character as the thousands separator.) ```csharp FormattableString str = $"Average grade is {s.Grades.Average()}"; var gradeStr = str.ToString(new System.Globalization.CultureInfo("de-DE")); ``` -For more information, see the [String interpolation](../language-reference/tokens/interpolated.md) article and the [String interpolation in C#](../tutorials/string-interpolation.md) tutorial. +To get started with string interpolation, check the [String interpolation in C#](../tutorials/intro-to-csharp/interpolated-strings.yml) interactive tutorial, the [String interpolation](../language-reference/tokens/interpolated.md) article, and the [String interpolation in C#](../tutorials/string-interpolation.md) tutorial. ## Exception filters -Another new feature in C# 6 is *exception filters*. Exception Filters -are clauses that determine when a given catch clause should be applied. -If the expression used for an exception filter evaluates to `true`, the -catch clause performs its normal processing on an exception. If the -expression evaluates to `false`, then the `catch` clause is skipped. - -One use is to examine information about an exception to determine if a -`catch` clause can process the exception: +*Exception Filters* are clauses that determine when a given catch clause should be applied. If the expression used for an exception filter evaluates to `true`, the catch clause performs its normal processing on an exception. If the +expression evaluates to `false`, then the `catch` clause is skipped. One use is to examine information about an exception to determine if a `catch` clause can process the exception: [!code-csharp[ExceptionFilter](../../../samples/snippets/csharp/new-in-6/NetworkClient.cs#ExceptionFilter)] -The code generated by exception filters provides better information about -an exception that is thrown and not processed. Before exception filters -were added to the language, you would need to create code like the following: - -[!code-csharp[ExceptionFilterOld](../../../samples/snippets/csharp/new-in-6/NetworkClient.cs#ExceptionFilterOld)] - -The point where the exception is thrown changes between these two examples. -In the previous code, where a `throw` clause is used, any stack trace -analysis or examination of crash dumps will show that the exception was -thrown from the `throw` statement in your catch clause. The actual exception -object will contain the original call stack, but all other information -about any variables in the call stack between this throw point and the -location of the original throw point has been lost. - -Contrast that with how the code using an exception filter is processed: -the exception filter expression evaluates to `false`. Therefore, execution never -enters the `catch` clause. Because the `catch` clause does not execute, -no stack unwinding takes place. That means the original -throw location is preserved for any debugging activities that would take -place later. - -Whenever you need to evaluate fields or properties of an exception, instead -of relying solely on the exception type, use an exception filter to -preserve more debugging information. - -Another recommended pattern with exception filters is to use them for -logging routines. This usage also leverages the manner in which the exception -throw point is preserved when an exception filter evaluates to `false`. - -A logging method would be a method whose argument is the exception that -unconditionally returns `false`: - -[!code-csharp[ExceptionFilterLogging](../../../samples/snippets/csharp/new-in-6/ExceptionFilterHelpers.cs#ExceptionFilterLogging)] - -Whenever you want to log an exception, you can add a catch clause, and -use this method as the exception filter: - -[!code-csharp[LogException](../../../samples/snippets/csharp/new-in-6/program.cs#LogException)] - -The exceptions are never caught, because the `LogException` method always -returns `false`. That always false exception filter means that you can -place this logging handler before any other exception handlers: - -[!code-csharp[LogExceptionRecovery](../../../samples/snippets/csharp/new-in-6/program.cs#LogExceptionRecovery)] - -The preceding example highlights a very important facet of exception filters. -The exception filters enable scenarios where a more general exception -catch clause may appear before a more specific one. It's also possible -to have the same exception type appear in multiple catch clauses: - -[!code-csharp[HandleNotChanged](../../../samples/snippets/csharp/new-in-6/NetworkClient.cs#HandleNotChanged)] - -Another recommended pattern helps prevent catch clauses from processing -exceptions when a debugger is attached. This technique enables you to -run an application with the debugger, and stop execution when an exception -is thrown. - -In your code, add an exception filter so that any recovery code executes -only when a debugger is not attached: - -[!code-csharp[LogExceptionDebugger](../../../samples/snippets/csharp/new-in-6/program.cs#LogExceptionDebugger)] - -After adding this in code, you set your debugger to break on all unhandled -exceptions. Run the program under the debugger, and the debugger breaks -whenever `PerformFailingOperation()` throws a `RecoverableException`. -The debugger breaks your program, because the catch clause won't be executed -due to the false-returning exception filter. - ## The `nameof` expression -The `nameof` expression evaluates to the name of a symbol. It's a great -way to get tools working whenever you need the name of a variable, -a property, or a member field. - -One of the most common uses for `nameof` is to provide the name of a symbol -that caused an exception: +The `nameof` expression evaluates to the name of a symbol. It's a great way to get tools working whenever you need the name of a variable, a property, or a member field. One of the most common uses for `nameof` is to provide the name of a symbol that caused an exception: [!code-csharp[nameof](../../../samples/snippets/csharp/new-in-6/NewCode.cs#UsingStaticString)] -Another use is with XAML based applications that implement the `INotifyPropertyChanged` -interface: +Another use is with XAML-based applications that implement the `INotifyPropertyChanged` interface: [!code-csharp[nameofNotify](../../../samples/snippets/csharp/new-in-6/viewmodel.cs#nameofNotify)] -The advantage of using the `nameof` operator over a constant string is -that tools can understand the symbol. If you use refactoring tools to -rename the symbol, it will rename it in the `nameof` expression. Constant -strings don't have that advantage. Try it yourself in your favorite editor: -rename a variable, and any `nameof` expressions will update as well. - -The `nameof` expression produces the unqualified name of its argument -(`LastName` in the previous examples) even if you use the fully qualified -name for the argument: - -[!code-csharp[QualifiedNameofNotify](../../../samples/snippets/csharp/new-in-6/viewmodel.cs#QualifiedNameofNotify)] - -This `nameof` expression produces `FirstName`, not `UXComponents.ViewModel.FirstName`. - ## Await in Catch and Finally blocks -C# 5 had several limitations around where you could place `await` expressions. -One of those has been removed in C# 6. You can now use `await` in `catch` -or `finally` expressions. - -The addition of await expressions in catch and finally blocks may appear -to complicate how those are processed. Let's add an example to discuss -how this appears. In any async method, you can use an await expression -in a finally clause. - -With C# 6, you can also await in catch expressions. This is most often -used with logging scenarios: +C# 5 had several limitations around where you could place `await` expressions. You can now use `await` in `catch` or `finally` expressions. With C# 6, you can also await in catch expressions. This is most often used with logging scenarios: [!code-csharp[AwaitFinally](../../../samples/snippets/csharp/new-in-6/NetworkClient.cs#AwaitFinally)] -The implementation details for adding `await` support inside `catch` -and `finally` clauses ensures that the behavior is consistent with the -behavior for synchronous code. When code executed in a `catch` or `finally` -clause throws, execution looks for a suitable `catch` clause in the next -surrounding block. If there was a current exception, that exception is -lost. The same happens with awaited expressions in `catch` and `finally` -clauses: a suitable `catch` is searched for, and the current exception, -if any, is lost. +The implementation details for adding `await` support inside `catch` and `finally` clauses ensure that the behavior is consistent with the behavior for synchronous code. When code executed in a `catch` or `finally` clause throws, execution looks for a suitable `catch` clause in the next surrounding block. If there was a current exception, that exception is lost. The same happens with awaited expressions in `catch` and `finally` clauses: a suitable `catch` is searched for, and the current exception, if any, is lost. > [!NOTE] -> This behavior is the reason it's recommended to write `catch` and `finally` -> clauses carefully, to avoid introducing new exceptions. +> This behavior is the reason it's recommended to write `catch` and `finally` clauses carefully, to avoid introducing new exceptions. ## Index initializers -*Index Initializers* is one of two features that make collection -initializers more consistent with index usage. In earlier releases of C#, you could use -*collection initializers* only with sequence style collections, including by adding braces around key and value pairs: +*Index Initializers* is one of two features that make collection initializers more consistent with index usage. In earlier releases of C#, you could use *collection initializers* only with sequence style collections, including by adding braces around key and value pairs: [!code-csharp[ListInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#ListInitializer)] -Now, you can use them with collections and similar types. The new syntax supports assignment using an index into the collection: +Now, you can use them with collections and other types where the accessible `Add` method accepts more than one argument. The new syntax supports assignment using an index into the collection: [!code-csharp[DictionaryInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#DictionaryInitializer)] -This feature means that associative containers can be initialized using -syntax similar to what's been in place for sequence containers for several -versions. +This feature means that associative containers can be initialized using syntax similar to what's been in place for sequence containers for several versions. ## Extension `Add` methods in collection initializers -Another feature that makes collection initialization easier is the ability -to use an *extension method* for the `Add` method. This feature was -added for parity with Visual Basic. - -The feature is most useful when you have a custom collection class that -has a method with a different name to semantically add new items. - -For example, consider a collection of students like this: - -[!code-csharp[Enrollment](../../../samples/snippets/csharp/new-in-6/enrollment.cs#Enrollment)] - -The `Enroll` method adds a student. But it doesn't follow the `Add` pattern. -In previous versions of C#, you could not use collection initializers with an -`Enrollment` object: - -[!code-csharp[InitializeEnrollment](../../../samples/snippets/csharp/new-in-6/classList.cs#InitializeEnrollment)] - -Now you can, but only if you create an extension method that maps `Add` to -`Enroll`: - -[!code-csharp[ExtensionAdd](../../../samples/snippets/csharp/new-in-6/classList.cs#ExtensionAdd)] - -What you are doing with this feature is to map whatever method adds -items to a collection to a method named `Add` by creating an -extension method. +Another feature that makes collection initialization easier is the ability to use an *extension method* for the `Add` method. This feature was added for parity with Visual Basic. The feature is most useful when you have a custom collection class that has a method with a different name to semantically add new items. ## Improved overload resolution -This last feature is one you probably won't notice. There were constructs -where the previous version of the C# compiler may have found some method -calls involving lambda expressions ambiguous. Consider this method: +This last feature is one you probably won't notice. There were constructs where the previous version of the C# compiler may have found some method calls involving lambda expressions ambiguous. Consider this method: [!code-csharp[AsyncMethod](../../../samples/snippets/csharp/new-in-6/overloads.cs#AsyncMethod)] -In earlier versions of C#, calling that method using the method group -syntax would fail: +In earlier versions of C#, calling that method using the method group syntax would fail: [!code-csharp[MethodGroup](../../../samples/snippets/csharp/new-in-6/overloads.cs#MethodGroup)] - -The earlier compiler could not distinguish correctly between `Task.Run(Action)` -and `Task.Run(Func())`. In previous versions, you'd need to use -a lambda expression as an argument: + +The earlier compiler couldn't distinguish correctly between `Task.Run(Action)` and `Task.Run(Func())`. In previous versions, you'd need to use a lambda expression as an argument: [!code-csharp[Lambda](../../../samples/snippets/csharp/new-in-6/overloads.cs#Lambda)] -The C# 6 compiler correctly determines that `Task.Run(Func())` is -a better choice. +The C# 6 compiler correctly determines that `Task.Run(Func())` is a better choice. ### Deterministic compiler output From cfc2330fafd91f409fea854b5b7fe3820ccbe60e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 14 Dec 2018 17:28:23 -0500 Subject: [PATCH 02/46] Add the YAML tutorial --- .../csharp/tutorials/exploration/csharp-6.yml | 297 ++++++++++++++++++ docs/csharp/tutorials/index.md | 4 + docs/csharp/whats-new/csharp-6.md | 6 +- docs/toc.md | 1 + 4 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 docs/csharp/tutorials/exploration/csharp-6.yml diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml new file mode 100644 index 0000000000000..886cd53da1ac0 --- /dev/null +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -0,0 +1,297 @@ +### YamlMime:Tutorial +title: Explore C# 6 - C# interactive C# tutorial +metadata: + title: Explore C# 6 - Try the new features in C# 6 interactively, using your browser + description: In this tutorial, you'll use your browser to explore C# 6 interactively. You'll explore the new idioms you can use with C# 6 that enable more concise and readable code. + audience: Developer + level: intermediate + ms.date: 12/11/2018 + displayType: two-column + interactive: csharp +items: +- durationInMinutes: 1 + content: | + This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. +- title: Read only auto-properties enable readonly types + durationInMinutes: 2 + content: | + Two enhancements to auto-property syntax make it easier to use auto-properties in more places: read-only auto-properties and auto-property initializers. Consider this small program: + + ```csharp + using System; + + public class Person + { + public string FirstName { get; private set; } + public string LastName { get; private set; } + + public Person(string first, string last) + { + FirstName = first; + LastName = last; + } + + public override string ToString() + { + return FirstName + " " + LastName; + } + + public string AllCaps() + { + FirstName = FirstName.ToUpper(); + LastName = LastName.ToUpper(); + return ToString(); + } + } + + public class Program + { + public static void Main() + { + var p = new Person("Bill", "Wagner"); + Console.WriteLine("The name, in all caps " + p.AllCaps()); + Console.WriteLine("The name " + p); + } + } + ``` + + Click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be readonly. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a reaonly auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: + + ```csharp + public string AllCaps() + { + return FirstName.ToUpper() + " " + LastName.ToUpper(); + } + ``` + + Using this new syntax, the compiler ensures that the properties are immutable. + +- title: Initialize backing fields for auto-properties + durationInMinutes: 1 + content: | + New syntax in C# 6 enables you to use initializers for auto-properties. This becomes more important as classes grow new capabilities. Add a middle name property, and a new constructor that takes three strings to your `Person` class: + + ```csharp + public string MiddleName { get; } = ""; + + public Person(string first, string middle, string last) + { + FirstName = first; + MiddleName = middle; + LastName = last; + } + ``` + + The assignment on the `MiddleName` property is an initializer. It initializes the compiler-generated backing field for the middle name. + +- title: Expression-bodied members + durationInMinutes: 2 + content: | + Expression-bodied members provide a lightweight syntax for lightweight methods. The `Person` class has two great candidates. Replace the declaration of `ToString` with the following code: + + ```csharp + public override string ToString() => FirstName + " " + LastName; + ``` + + Try the same with the `Caps` method. This is a small improvement, but when used wisely it creates much more readable code, especially for Data Transfer Objects (DTOs) and other types with minimal behavior. + +- title: importing a single class + durationInMinutes: 2 + content: | + You may use a class' static methods throughout our code. Repeatedly typing the class name obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even those only is used. Modify the `using` statement as follows: + + ```csharp + using static System.Console; + ``` + + The `static using` statement becomes more useful in larger programs that make extensive use of a single class with many static methods, like the `string` class or the class. + +- title: A better string format + durationInMinutes: 2 + content: | + C# 6 contains new syntax for composing strings from a string and embedded expressions that are evaluated to produce other string values. You can change the `ToString` and `AllCaps` methods to use this syntax: + + ```csharp + public override string ToString() => $"{FirstName} {LastName}"; + public string AllCaps() => $"{FirstName.ToUpper()} {LastName.ToUpper()}"; + ``` + + Instead of positional arguments between the `{` and `}`, you write C# expressions directly. You can do the same in the `Main` method. Replace the existing code with the following: + + ```csharp + var p = new Person("Bill", "Wagner"); + Console.WriteLine($"The name, in all caps {p.AllCaps()}"); + Console.WriteLine($"The name is {p}"); + ``` + + You're not limited to a single variable in these expressions. Let's start with a new example and modify it to demonstrate. Paste the following code into the interactive window in the `Main` method: + + ```csharp + var phrase = "the quick brown fox jumps over the lazy dog"; + var wordLength = from word in phrase.Split(" ") select word.Length; + var average = wordLength.Average(); + Console.WriteLine(average); + ``` + + You can remove the local variable `average` and perform that calculation as part of the interpolated string expression. Replace the last two lines with the following: + + ```csharp + Console.WriteLine($"The average word length is: {wordLength.Average()}"); + ``` + + Running the preceding example, you would find that the output for `Average()` has more decimal places than you would like. The string interpolation syntax supports all the format strings available using earlier formatting methods. You specify the format string inside the braces. Add a `:` following the expression to format: + + ```csharp + Console.WriteLine($"The average word length is: {wordLength.Average():F2}"); + ``` + +- title: Quick and easy null checks + durationInMinutes: 2 + content: | + The `?.` operator makes it easier to write logic that takes `null` values into account seamlessly, without extra `if` checks. To explore the feature, start by copying the following code into the interactive window to try it: + + ```csharp + using System; + + public class Program + { + public static void Main() + { + string s = null; + Console.WriteLine(s.Length); + } + } + ``` + + It throws a . Change the `.` member access to the **null conditional operator**: + + ```csharp + Console.WriteLine(s?.Length); + ``` + + After this change, there's no output. That's because the result of `s?.Length` is a `int?` whose value in this example is `null`. The `?.` returns `null` if its left operand is `null`. If the type of the right operand is a value type, the `?.` operator returns a nullable type for that type. In addition to `?.` you can use `?[]` for array or indexer access. Try the following code in the interactive window: + + ```csharp + char? c = s?[0]; + Console.WriteLine(c.HasValue); + ``` + + The null conditional operator composes, making it easy to avoid nested if clauses to access members of members. For example, try the following code in the interactive window: + + ```csharp + string s = null; + bool? hasMore = s?.ToCharArray()?.GetEnumerator()?.MoveNext(); + Console.WriteLine(hasMore.HasValue); + ``` + + The preceding example can be simplified by using the **null coalescing operator** to provide a default value: + + ```csharp + bool hasMore = s?.ToCharArray()?.GetEnumerator()?.MoveNext() ?? false; + Console.WriteLine(hasMore); + ``` + + The **null conditional operator** helps you write code that makes your core logic clear while seamlessly testing for `null` values. + +- title: Exception filers + durationInMinutes: 2 + content: | + Exception filters enable you to catch an exception based on some condition. A typical use is to create a filter method that logs exceptions and always returns false. Try the following code in the interactive window: It logs the exception type and message to the console. It returns false which indicates that the exception can't be handled. Try the program in the interactive window. + + ```csharp + using System; + + public class Program + { + public static void Main() + { + try + { + string s = null; + Console.WriteLine(s.Length); + + bool? hasMore = s?.ToCharArray()?.GetEnumerator()?.MoveNext(); + Console.WriteLine(hasMore.HasValue); + } catch (Exception e) when (LogException(e)) + { + } + Console.WriteLine("Exception must have been handled"); + } + + private static bool LogException(Exception e) + { + Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}"); + Console.WriteLine($"\tMessage: {e.Message}"); + return false; + } + } + ``` + + You should have seen the message from the log method, followed by the default exception message. Just to experiment, change the `return false` statement to `return true` and run this again. Now, the exception is caught and the program runs to completion. + + Beyond logging scenarios, exception filters can be most useful when a property of the exception determines what action to take. Consider looking inside an to see what the contained exceptions are. + +- title: using nameof + durationInMinutes: 2 + content: | + The `nameof` operator returns the name of any variable or type. Try the following code in the interactive window to see how it works: + + ```csharp + using System; + + public class Program + { + public static void Main() + { + Console.WriteLine(nameof(System.String)); + int j = 5; + Console.WriteLine(nameof(j)); + List names = new List(); + Console.WriteLine(nameof(names)); + } + } + ``` + + The output matches the name of the variable or type. Even when you provided the fully-qualified type name (such as `System.String`) the `nameof` operator returns the unqualified name. This feature is most useful when you need to convert a parameter or property name to a string. Examples include throwing or , or implementing . + +- title: New object initialization syntax + durationInMinutes: 2 + content: | + New object initialization enables you to create methods that make it easier to initialize dictionaries, and other types. Start with a dictionary. Run the following code in the interactive window: + + ```csharp + var messages = new Dictionary + { + [404] = "Page not Found", + [302] = "Page moved, but left a forwarding address.", + [500] = "The web server can't come out to play today." + }; + + Console.WriteLine(messages[302]); + ``` + + You can extend this syntax to any class that implements and has a publicly accessible `Add` method. Try the following sample in the interactive window. It creates a `Path` class that implements `IEnumerable` and has a method to add points that takes three arguments. It also combines other techniques already demonstrated in this tutorial such as expression bodied members, and string interpolation. + + In the `Main` method, you initialize a path by providing coordinates for the points. Those points are added to the collection through the `Add` method. + + The Add method can also be an extension method. You could update the preceding sample as follows. This sample won't compile in the interactive experience because of sandbox limitations. You can try it on your own machine. + + ```csharp + public class Path : IEnumerable + { + private List points = new List(); + public IEnumerator GetEnumerator() => points.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => points.GetEnumerator(); + + public void Add(Point3D pt) => points.Add(pt); + } + + public static class Extensions + { + public static void Add(this Path path, double x, double y, double z) => path.Add(new Point3D(x, y, z)); + } + ``` + + - content: | + You've completed an exploration of the new features in C# 6. Now try them yourself in your applications. + \ No newline at end of file diff --git a/docs/csharp/tutorials/index.md b/docs/csharp/tutorials/index.md index 0abc756ecb562..e0f75363ee2fe 100644 --- a/docs/csharp/tutorials/index.md +++ b/docs/csharp/tutorials/index.md @@ -60,6 +60,10 @@ with the next lesson online or on your own machine. There are links to help you setup your environment and continue with the next tutorial on your machine. +## Explore new features in C# # + +Try new features in [C# 6](../whats-new/csharp-6.md) in this [interactive exploration](exploration/csharp6.yml) + ## General Tutorials The following tutorials enable you to build C# programs using [.NET Core](../../core/index.md): diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index e0ac881ab9431..6159bcd805774 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -83,11 +83,11 @@ The `static using` directive also imports any nested types. You can reference an ## Null-conditional operators -The *null conditional operator* makes null checks much easier and fluid. Replace the member access `.` with `?.` and use expressions between `{` and `}` instead of ordinals: +The *null conditional operator* makes null checks much easier and fluid. Replace the member access `.` with `?.`: [!code-csharp[NullConditional](../../../samples/snippets/csharp/new-in-6/program.cs#NullConditional)] -In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it gets assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` when the `person` variable is `null`. Instead, it short-circuits and produces `null`. +In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it gets assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` when the `person` variable is `null`. Instead, it short-circuits and produces `null`. You can also use a null conditional operator for array or indexer access. Replace `[]` with `?[]` in the index expression. This expression returns a `string`, regardless of the value of `person`. When the expression short-circuits, the `null` value returned is typed to match the full expression. @@ -109,7 +109,7 @@ Ensuring that the left side is evaluated only once also enables you to use any e ## String interpolation -With C# 6, the new [string interpolation](../language-reference/tokens/interpolated.md) feature enables you to embed the expressions in a string. Simply preface the string with `$`: +With C# 6, the new [string interpolation](../language-reference/tokens/interpolated.md) feature enables you to embed the expressions in a string. Simply preface the string with `$`and use expressions between `{` and `}` instead of ordinals: [!code-csharp[stringInterpolation](../../../samples/snippets/csharp/new-in-6/newcode.cs#FullNameExpressionMember)] diff --git a/docs/toc.md b/docs/toc.md index f503cdf2a8f10..97c69d581cefe 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -246,6 +246,7 @@ ##### [String interpolation](csharp/tutorials/intro-to-csharp/interpolated-strings-local.md) ##### [List collections](csharp/tutorials/intro-to-csharp/arrays-and-collections.md) ##### [Introduction to classes](csharp/tutorials/intro-to-csharp/introduction-to-classes.md) +### [Explore C# 6](csharp/tutorials/exploration/csharp6.yml) ### [Work with nullable reference types](csharp/tutorials/nullable-reference-types.md) ### [Console Application](csharp/tutorials/console-teleprompter.md) ### [REST Client](csharp/tutorials/console-webapiclient.md) From 2b3f114f90b645d12303805463712b5bee7dcdb3 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 14 Dec 2018 17:34:09 -0500 Subject: [PATCH 03/46] fix a YAML issue --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 886cd53da1ac0..c14dcd9aa869a 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -292,6 +292,6 @@ items: } ``` - - content: | +- content: | You've completed an exploration of the new features in C# 6. Now try them yourself in your applications. \ No newline at end of file From 59a77c1faa28a0cf4bd7f4e7256498836b833b8d Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 14 Dec 2018 17:43:43 -0500 Subject: [PATCH 04/46] fix a build error --- docs/csharp/tutorials/index.md | 2 +- docs/toc.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/tutorials/index.md b/docs/csharp/tutorials/index.md index e0f75363ee2fe..47fe2fdeb3a3d 100644 --- a/docs/csharp/tutorials/index.md +++ b/docs/csharp/tutorials/index.md @@ -62,7 +62,7 @@ on your machine. ## Explore new features in C# # -Try new features in [C# 6](../whats-new/csharp-6.md) in this [interactive exploration](exploration/csharp6.yml) +Try new features in [C# 6](../whats-new/csharp-6.md) in this [interactive exploration](exploration/csharp-6.yml) ## General Tutorials diff --git a/docs/toc.md b/docs/toc.md index 97c69d581cefe..c9fef63e4d556 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -246,7 +246,7 @@ ##### [String interpolation](csharp/tutorials/intro-to-csharp/interpolated-strings-local.md) ##### [List collections](csharp/tutorials/intro-to-csharp/arrays-and-collections.md) ##### [Introduction to classes](csharp/tutorials/intro-to-csharp/introduction-to-classes.md) -### [Explore C# 6](csharp/tutorials/exploration/csharp6.yml) +### [Explore C# 6](csharp/tutorials/exploration/csharp-6.yml) ### [Work with nullable reference types](csharp/tutorials/nullable-reference-types.md) ### [Console Application](csharp/tutorials/console-teleprompter.md) ### [REST Client](csharp/tutorials/console-webapiclient.md) From 9e3cf9081c4bb90dc0386fe99aa8752b3a9d75db Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 20 Dec 2018 14:33:59 -0500 Subject: [PATCH 05/46] update interactive samples How tos are done. Links for new exploration tutorials are done. --- ...tionary-with-a-collection-initializer_1.cs | 16 -- ...bjects-by-using-an-object-initializer_1.cs | 77 ---------- ...bjects-by-using-an-object-initializer_2.cs | 7 - .../object-and-collection-initializers_1.cs | 6 - .../object-and-collection-initializers_2.cs | 1 - .../object-and-collection-initializers_3.cs | 3 - .../object-and-collection-initializers_4.cs | 6 - .../object-and-collection-initializers_5.cs | 6 - .../object-and-collection-initializers_6.cs | 49 ------ .../object-and-collection-initializers_7.cs | 53 ------- .../object-and-collection-initializers_8.cs | 104 ------------- ...ictionary-with-a-collection-initializer.md | 14 +- ...-objects-by-using-an-object-initializer.md | 30 ++-- .../object-and-collection-initializers.md | 143 +++++++++++------- .../csharp/tutorials/exploration/csharp-6.yml | 83 ++-------- docs/csharp/whats-new/csharp-6.md | 2 +- 16 files changed, 121 insertions(+), 479 deletions(-) delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-a-dictionary-with-a-collection-initializer_1.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_1.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_2.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_1.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_2.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_3.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_4.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_5.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_6.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_7.cs delete mode 100644 docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_8.cs diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-a-dictionary-with-a-collection-initializer_1.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-a-dictionary-with-a-collection-initializer_1.cs deleted file mode 100644 index 6271f1b0d2faf..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-a-dictionary-with-a-collection-initializer_1.cs +++ /dev/null @@ -1,16 +0,0 @@ - class StudentName - { - public string FirstName { get; set; } - public string LastName { get; set; } - public int ID { get; set; } - } - - class CollInit - { - Dictionary students = new Dictionary() - { - { 111, new StudentName { FirstName="Sachin", LastName="Karnik", ID=211 } }, - { 112, new StudentName { FirstName="Dina", LastName="Salimzianova", ID=317 } }, - { 113, new StudentName { FirstName="Andy", LastName="Ruth", ID=198 } } - }; - } diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_1.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_1.cs deleted file mode 100644 index 7ca2f754cf8a4..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_1.cs +++ /dev/null @@ -1,77 +0,0 @@ - public class Program - { - public static void Main() - { - - // Declare a StudentName by using the constructor that has two parameters. - StudentName student1 = new StudentName("Craig", "Playstead"); - - // Make the same declaration by using an object initializer and sending - // arguments for the first and last names. The default constructor is - // invoked in processing this declaration, not the constructor that has - // two parameters. - StudentName student2 = new StudentName - { - FirstName = "Craig", - LastName = "Playstead", - }; - - // Declare a StudentName by using an object initializer and sending - // an argument for only the ID property. No corresponding constructor is - // necessary. Only the default constructor is used to process object - // initializers. - StudentName student3 = new StudentName - { - ID = 183 - }; - - // Declare a StudentName by using an object initializer and sending - // arguments for all three properties. No corresponding constructor is - // defined in the class. - StudentName student4 = new StudentName - { - FirstName = "Craig", - LastName = "Playstead", - ID = 116 - }; - - System.Console.WriteLine(student1.ToString()); - System.Console.WriteLine(student2.ToString()); - System.Console.WriteLine(student3.ToString()); - System.Console.WriteLine(student4.ToString()); - } - - // Output: - // Craig 0 - // Craig 0 - // 183 - // Craig 116 - } - - public class StudentName - { - // The default constructor has no parameters. The default constructor - // is invoked in the processing of object initializers. - // You can test this by changing the access modifier from public to - // private. The declarations in Main that use object initializers will - // fail. - public StudentName() { } - - // The following constructor has parameters for two of the three - // properties. - public StudentName(string first, string last) - { - FirstName = first; - LastName = last; - } - - // Properties. - public string FirstName { get; set; } - public string LastName { get; set; } - public int ID { get; set; } - - public override string ToString() - { - return FirstName + " " + ID; - } - } \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_2.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_2.cs deleted file mode 100644 index 521329a78f381..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_2.cs +++ /dev/null @@ -1,7 +0,0 @@ - List students = new List() - { - new StudentName { FirstName="Craig", LastName="Playstead", ID=116 }, - new StudentName { FirstName="Shu", LastName="Ito", ID=112 }, - new StudentName { FirstName="Gretchen", LastName="Rivas", ID=113 }, - new StudentName { FirstName="Rajesh", LastName="Rotti", ID=114 } - }; diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_1.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_1.cs deleted file mode 100644 index 86a343ddc989d..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_1.cs +++ /dev/null @@ -1,6 +0,0 @@ - class Cat - { - // Auto-implemented properties. - public int Age { get; set; } - public string Name { get; set; } - } \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_2.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_2.cs deleted file mode 100644 index d9c181085eb0e..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_2.cs +++ /dev/null @@ -1 +0,0 @@ - Cat cat = new Cat { Age = 10, Name = "Fluffy" }; \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_3.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_3.cs deleted file mode 100644 index 2ab4a8a3acbec..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_3.cs +++ /dev/null @@ -1,3 +0,0 @@ - var productInfos = - from p in products - select new { p.ProductName, p.UnitPrice }; \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_4.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_4.cs deleted file mode 100644 index f20b9f13c329b..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_4.cs +++ /dev/null @@ -1,6 +0,0 @@ - List cats = new List - { - new Cat(){ Name = "Sylvester", Age=8 }, - new Cat(){ Name = "Whiskers", Age=2 }, - new Cat(){ Name = "Sasha", Age=14 } - }; \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_5.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_5.cs deleted file mode 100644 index 0d63f6d6734e2..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_5.cs +++ /dev/null @@ -1,6 +0,0 @@ - List moreCats = new List - { - new Cat(){ Name = "Furrytail", Age=5 }, - new Cat(){ Name = "Peaches", Age=4 }, - null - }; \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_6.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_6.cs deleted file mode 100644 index 25c3f5a4510d6..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_6.cs +++ /dev/null @@ -1,49 +0,0 @@ - // The following code consolidates examples from the topic. - class ObjInitializers - { - class Cat - { - // Auto-implemented properties. - public int Age { get; set; } - public string Name { get; set; } - } - - static void Main() - { - Cat cat = new Cat { Age = 10, Name = "Fluffy" }; - - List cats = new List - { - new Cat(){ Name = "Sylvester", Age=8 }, - new Cat(){ Name = "Whiskers", Age=2 }, - new Cat(){ Name = "Sasha", Age=14 } - }; - - List moreCats = new List - { - new Cat(){ Name = "Furrytail", Age=5 }, - new Cat(){ Name = "Peaches", Age=4 }, - null - }; - - // Display results. - System.Console.WriteLine(cat.Name); - - foreach (Cat c in cats) - System.Console.WriteLine(c.Name); - - foreach (Cat c in moreCats) - if (c != null) - System.Console.WriteLine(c.Name); - else - System.Console.WriteLine("List element has null value."); - } - // Output: - //Fluffy - //Sylvester - //Whiskers - //Sasha - //Furrytail - //Peaches - //List element has null value. - } \ No newline at end of file diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_7.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_7.cs deleted file mode 100644 index 2ed3575b05bff..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_7.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace ExampleProject -{ - class FormattedAddresses : IEnumerable - { - private List internalList = new List(); - public IEnumerator GetEnumerator() => internalList.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => internalList.GetEnumerator(); - - public void Add(string firstname, string lastname, string street, string city, string state, string zipcode) => internalList.Add( - $@"{firstname} {lastname} -{street} -{city}, {state} {zipcode}" - ); - } - - class Program - { - static void Main(string[] args) - { - FormattedAddresses addresses = new FormattedAddresses() - { - {"John", "Doe", "123 Street", "Topeka", "KS", "00000" }, - {"Jane", "Smith", "456 Street", "Topeka", "KS", "00000" } - }; - - Console.WriteLine("Address Entries:"); - - foreach(string addressEntry in addresses) - { - Console.WriteLine("\r\n" + addressEntry); - } - } - - /* - * Prints: - - Address Entries: - - John Doe - 123 Street - Topeka, KS 00000 - - Jane Smith - 456 Street - Topeka, KS 00000 - */ - } -} diff --git a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_8.cs b/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_8.cs deleted file mode 100644 index ed507d36641a9..0000000000000 --- a/docs/csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_8.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace ExampleProject -{ - class RudimentaryMultiValuedDictionary : IEnumerable>> - { - private Dictionary> internalDictionary = new Dictionary>(); - - public IEnumerator>> GetEnumerator() => internalDictionary.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => internalDictionary.GetEnumerator(); - - public List this[TKey key] - { - get => internalDictionary[key]; - set => Add(key, value); - } - - public void Add(TKey key, params TValue[] values) => Add(key, (IEnumerable)values); - - public void Add(TKey key, IEnumerable values) - { - if (!internalDictionary.TryGetValue(key, out List storedValues)) - internalDictionary.Add(key, storedValues = new List()); - - storedValues.AddRange(values); - } - } - - class Program - { - static void Main(string[] args) - { - RudimentaryMultiValuedDictionary rudimentaryMultiValuedDictionary1 - = new RudimentaryMultiValuedDictionary() - { - {"Group1", "Bob", "John", "Mary" }, - {"Group2", "Eric", "Emily", "Debbie", "Jesse" } - }; - RudimentaryMultiValuedDictionary rudimentaryMultiValuedDictionary2 - = new RudimentaryMultiValuedDictionary() - { - ["Group1"] = new List() { "Bob", "John", "Mary" }, - ["Group2"] = new List() { "Eric", "Emily", "Debbie", "Jesse" } - }; - - Console.WriteLine("Using first multi-valued dictionary created with a collection initializer:"); - - foreach(KeyValuePair> group in rudimentaryMultiValuedDictionary1) - { - Console.WriteLine($"\r\nMembers of group {group.Key}: "); - - foreach(string member in group.Value) - { - Console.WriteLine(member); - } - } - - Console.WriteLine("\r\nUsing second multi-valued dictionary created with a collection initializer using indexing:"); - - foreach (KeyValuePair> group in rudimentaryMultiValuedDictionary2) - { - Console.WriteLine($"\r\nMembers of group {group.Key}: "); - - foreach (string member in group.Value) - { - Console.WriteLine(member); - } - } - } - - /* - * Prints: - - Using first multi-valued dictionary created with a collection initializer: - - Members of group Group1: - Bob - John - Mary - - Members of group Group2: - Eric - Emily - Debbie - Jesse - - Using second multi-valued dictionary created with a collection initializer using indexing: - - Members of group Group1: - Bob - John - Mary - - Members of group Group2: - Eric - Emily - Debbie - Jesse - */ - } -} diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md index a9185a6df9246..03b2ae1ffb16b 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md @@ -1,26 +1,22 @@ --- title: "How to initialize a dictionary with a collection initializer - C# Programming Guide" ms.custom: seodec18 -ms.date: 07/20/2015 +ms.date: 12/20/2018 helpviewer_keywords: - "collection initializers [C#], with Dictionary" ms.assetid: 25283922-f8ee-40dc-a639-fac30804ec71 --- # How to initialize a dictionary with a collection initializer (C# Programming Guide) -A contains a collection of key/value pairs. Its method takes two parameters, one for the key and one for the value. To initialize a , or any collection whose `Add` method takes multiple parameters, enclose each set of parameters in braces as shown in the following example. +A contains a collection of key/value pairs. Its method takes two parameters, one for the key and one for the value. One way to initialize a , or any collection whose `Add` method takes multiple parameters, enclose each set of parameters in braces as shown in the following example. Another option is to use an index initializer, also shown in the following example. ## Example -In the following code example, a is initialized with instances of type `StudentName`. - -[!code-csharp[csProgGuideLINQ#34](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-a-dictionary-with-a-collection-initializer_1.cs)] +In the following code example, a is initialized with instances of type `StudentName`. The first initialization uses the `Add` method with two arguments. The second uses the indexer method of the `Dictionary` class: -Note the two pairs of braces in each element of the collection. The innermost braces enclose the object initializer for the `StudentName`, and the outermost braces enclose the initializer for the key/value pair that will be added to the `students` . Finally, the whole collection initializer for the dictionary is enclosed in braces. +[!code-csharp-interactive[InitializerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToDictionaryInitializer.cs#HowToDictionaryInitializer)] -## Compiling the code - -To run this code, copy and paste the class into a Visual C# console application project that has been created in Visual Studio. By default, this project targets version 3.5 of the [!INCLUDE[dnprdnshort](~/includes/dnprdnshort-md.md)], and it has a reference to System.Core.dll and a using directive for System.Linq. If one or more of these requirements are missing from the project, you can add them manually. +Note the two pairs of braces in each element of the collection in the first declaration. The innermost braces enclose the object initializer for the `StudentName`, and the outermost braces enclose the initializer for the key/value pair that will be added to the `students` . Finally, the whole collection initializer for the dictionary is enclosed in braces. In the second initialization, the left side of the assignment is the key and the right side is the value, using an object initializer for `StudentName`. ## See also diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md index 0016f5ae6508d..7797ee8cc29a1 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md @@ -1,33 +1,31 @@ --- title: "How to: Initialize Objects by Using an Object Initializer - C# Programming Guide" ms.custom: seodec18 -ms.date: 07/20/2015 +ms.date: 12/20/2018 helpviewer_keywords: - "object initializers [C#], how to use" - "objects [C#], initializing" ms.assetid: 4b75ebb2-2e29-43de-929c-d736a8f27ce6 --- # How to: Initialize Objects by Using an Object Initializer (C# Programming Guide) + You can use object initializers to initialize type objects in a declarative manner without explicitly invoking a constructor for the type. - The following examples show how to use object initializers with named objects. The compiler processes object initializers by first accessing the default instance constructor and then processing the member initializations. Therefore, if the default constructor is declared as `private` in the class, object initializers that require public access will fail. +The following examples show how to use object initializers with named objects. The compiler processes object initializers by first accessing the default instance constructor and then processing the member initializations. Therefore, if the default constructor is declared as `private` in the class, object initializers that require public access will fail. - You must use an object initializer if you're defining an anonymous type. For more information, see [How to: Return Subsets of Element Properties in a Query](../../../csharp/programming-guide/classes-and-structs/how-to-return-subsets-of-element-properties-in-a-query.md). +You must use an object initializer if you're defining an anonymous type. For more information, see [How to: Return Subsets of Element Properties in a Query](how-to-return-subsets-of-element-properties-in-a-query.md). ## Example - The following example shows how to initialize a new `StudentName` type by using object initializers. - - [!code-csharp[csProgGuideLINQ#35](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_1.cs)] - -## Example - The following example shows how to initialize a collection of `StudentName` types by using a collection initializer. Note that a collection initializer is a series of comma-separated object initializers. - - [!code-csharp[csProgGuideLINQ#36](../../../csharp/programming-guide/arrays/codesnippet/CSharp/how-to-initialize-objects-by-using-an-object-initializer_2.cs)] - -## Compiling the Code - To run this code, copy and paste the class into a Visual C# console application project that has been created in Visual Studio. + +The following example shows how to initialize a new `StudentName` type by using object initializers. This example sets properties in the `StudentName` type: +[!code-csharp-interactive[InitializerObjectExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToObjectInitializer.cs#HowToObjectInitializers)] + +Object initializers can be used to set indexers in an object. The following example defines a `BaseballTeam` class that uses an indexer to get and set players at different positions. The initializer can assign players, based on the abbreviation for the position, or the number used for each position baseball scorecards: + +[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializer.cs#HOwToIndexInitializer)] + ## See Also -- [C# Programming Guide](../../../csharp/programming-guide/index.md) -- [Object and Collection Initializers](../../../csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md) +- [C# Programming Guide](../index.md) +- [Object and Collection Initializers](object-and-collection-initializers.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index 5c57f8ded8b12..a5cbbe0ae9ea8 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -1,88 +1,121 @@ --- title: "Object and Collection Initializers - C# Programming Guide" ms.custom: seodec18 -ms.date: 07/20/2015 +ms.date: 12/19/2018 helpviewer_keywords: - "object initializers [C#]" - "collection initializers [C#]" ms.assetid: c58f3db5-d7d4-4651-bd2d-5a3a97357f61 --- # Object and Collection Initializers (C# Programming Guide) -Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. The object initializer syntax enables you to specify arguments for a constructor or omit the arguments (and parentheses syntax). The following example shows how to use an object initializer with a named type, `Cat` and how to invoke the default constructor. Note the use of auto-implemented properties in the `Cat` class. For more information, see [Auto-Implemented Properties](../../../csharp/programming-guide/classes-and-structs/auto-implemented-properties.md). - - [!code-csharp[csProgGuideLINQ#39](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_1.cs)] + +Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. The object initializer syntax enables you to specify arguments for a constructor or omit the arguments (and parentheses syntax). The following example shows how to use an object initializer with a named type, `Cat` and how to invoke the default constructor. Note the use of auto-implemented properties in the `Cat` class. For more information, see [Auto-Implemented Properties](auto-implemented-properties.md). - [!code-csharp[csProgGuideLINQ#45](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_2.cs)] +[!code-csharp[ObjectInitializer1](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#CatDeclaration)] +[!code-csharp[ObjectInitializer1a](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#ObjectPropertyInitialization)] The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment. - -## Object Initializers with anonymous types - Although object initializers can be used in any context, they are especially useful in [!INCLUDE[vbteclinq](~/includes/vbteclinq-md.md)] query expressions. Query expressions make frequent use of [anonymous types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md), which can only be initialized by using an object initializer, as shown in the following declaration. - + +Starting with C# 6, object initializers can set indexers, in addition to assigning fields and properties. Consider this basic `Matrix` class: + +[!code-csharp[ObjectInitializer2](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#MatrixDeclaration)] + +You could initialize the identity matrix with the following code: + +[!code-csharp[ObjectInitializer2a](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#MatrixInitialization)] + +Any accessible indexer that contains an accessible setter can be used as one of the expressions in an object initializer, regardless of the number or types of arguments. The index arguments form the left side of the assignment, and the value is the right side of the expression. For example, these are all valid if `IndexersExample` has the appropriate indexers: + +```csharp +var thing = new IndexersExample { + name = "object one", + [1] = '1', + [2] = '4', + [3] = '9', + Baz = Math.PI, + ['C',4] = "Middle C" +} +``` + +For the preceding code to compile, the `IndexersExample` type must have the following members: + +```csharp +public string name; +public double Size { set { ... }; } +public char this[int i] { set { ... }; } +public string this[char c, int i] { set { ... }; } +} +``` + +## Object Initializers with anonymous types + +Although object initializers can be used in any context, they are especially useful in [!INCLUDE[vbteclinq](~/includes/vbteclinq-md.md)] query expressions. Query expressions make frequent use of [anonymous types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md), which can only be initialized by using an object initializer, as shown in the following declaration. + ```csharp var pet = new { Age = 10, Name = "Fluffy" }; -``` - - Anonymous types enable the `select` clause in a [!INCLUDE[vbteclinq](~/includes/vbteclinq-md.md)] query expression to transform objects of the original sequence into objects whose value and shape may differ from the original. This is useful if you want to store only a part of the information from each object in a sequence. In the following example, assume that a product object (`p`) contains many fields and methods, and that you are only interested in creating a sequence of objects that contain the product name and the unit price. - - [!code-csharp[csProgGuideLINQ#40](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_3.cs)] - - When this query is executed, the `productInfos` variable will contain a sequence of objects that can be accessed in a `foreach` statement as shown in this example: +``` + +Anonymous types enable the `select` clause in a [!INCLUDE[vbteclinq](~/includes/vbteclinq-md.md)] query expression to transform objects of the original sequence into objects whose value and shape may differ from the original. This is useful if you want to store only a part of the information from each object in a sequence. In the following example, assume that a product object (`p`) contains many fields and methods, and that you are only interested in creating a sequence of objects that contain the product name and the unit price. +[!code-csharp[ObjectInitializer3](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#AnonymousUse)] + +When this query is executed, the `productInfos` variable will contain a sequence of objects that can be accessed in a `foreach` statement as shown in this example: + ```csharp foreach(var p in productInfos){...} -``` - - Each object in the new anonymous type has two public properties which receive the same names as the properties or fields in the original object. You can also rename a field when you are creating an anonymous type; the following example renames the `UnitPrice` field to `Price`. - +``` + +Each object in the new anonymous type has two public properties which receive the same names as the properties or fields in the original object. You can also rename a field when you are creating an anonymous type; the following example renames the `UnitPrice` field to `Price`. + ```csharp select new {p.ProductName, Price = p.UnitPrice}; -``` - -## Collection initializers - Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer you do not have to specify multiple calls to the `Add` method of the class in your source code; the compiler adds the calls. - - The following examples shows two simple collection initializers: +``` + +## Collection initializers + +Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer you do not have to specify multiple calls to the `Add` method of the class in your source code; the compiler adds the calls. +The following examples shows two simple collection initializers: + ```csharp List digits = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; List digits2 = new List { 0 + 1, 12 % 3, MakeInt() }; -``` - - The following collection initializer uses object initializers to initialize objects of the `Cat` class defined in a previous example. Note that the individual object initializers are enclosed in braces and separated by commas. - - [!code-csharp[csProgGuideLINQ#41](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_4.cs)] +``` + +The following collection initializer uses object initializers to initialize objects of the `Cat` class defined in a previous example. Note that the individual object initializers are enclosed in braces and separated by commas. - You can specify [null](../../../csharp/language-reference/keywords/null.md) as an element in a collection initializer if the collection's `Add` method allows it. +[!code-csharp[ListInitializer](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#ListInitializer)] - [!code-csharp[csProgGuideLINQ#42](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_5.cs)] +You can specify [null](../../language-reference/keywords/null.md) as an element in a collection initializer if the collection's `Add` method allows it. - You can specify indexed elements if the collection supports indexing. +[!code-csharp[ListInitializerNull](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#ListInitialerWithNull)] -```csharp -var numbers = new Dictionary { - [7] = "seven", - [9] = "nine", - [13] = "thirteen" -}; -``` + You can specify indexed elements if the collection supports indexing. +[!code-csharp[DictionaryInitializer](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#DictionaryIndexerInitializer)] + +The preceding sample generates code that calls the to set the values. Beginning with C# 6, you can initialize dictionaries and other associative containers using the following syntax. Notice that instead of indexer syntax, with parentheses and an assignment, it uses an object with multiple values: + +[!code-csharp[DictionaryAddInitializer](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#DictionaryAddInitializer)] + +This initializer example calls to add the three items into the dictionary. These two different ways to initialize associative collections have slightly different behavior because of the methods calls the compiler generates. Both variants work with the `Dictionary` class. Other types may only support one or the other based on their public API. + ## Examples - The following example combines the concepts of object and collection initializers. +The following example combines the concepts of object and collection initializers. + +[!code-csharp-interactive[InitializerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#FullExample)] + +Shown in the following example, an object which implements containing an `Add` method with multiple parameters allows for collection initializers with multiple elements per item in the list corresponding to the signature of the `Add` method. + +[!code-csharp-interactive[InitializerListExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#FullListExample)] + +`Add` methods can use the `params` keyword to take a variable number of arguments as shown in the following example. This example demonstrates the custom implementation of an indexer as well to initialize a collection using indexes. + +[!code-csharp-interactive[InitializerListExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#FullDictionaryInitializer)] - [!code-csharp[csProgGuideLINQ#46](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_6.cs)] - - Shown in the following example, an object which implements containing an `Add` method with multiple parameters allows for collection initializers with multiple elements per item in the list corresponding to the signature of the `Add` method. - - [!code-csharp[csProgGuideLINQ#84](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_7.cs)] - - `Add` methods can use the `params` keyword to take a variable number of arguments as shown in the following example. This example demonstrates the custom implementation of an indexer as well to initialize a collection using indexes. - - [!code-csharp[csProgGuideLINQ#85](../../../csharp/programming-guide/arrays/codesnippet/CSharp/object-and-collection-initializers_8.cs)] - ## See Also -- [C# Programming Guide](../../../csharp/programming-guide/index.md) -- [LINQ Query Expressions](../../../csharp/programming-guide/linq-query-expressions/index.md) -- [Anonymous Types](../../../csharp/programming-guide/classes-and-structs/anonymous-types.md) +- [C# Programming Guide](../index.md) +- [LINQ Query Expressions](../linq-query-expressions/index.md) +- [Anonymous Types](anonymous-types.md) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index c14dcd9aa869a..3ba4a8552498b 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -11,51 +11,17 @@ metadata: items: - durationInMinutes: 1 content: | - This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. + This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can read about the features in the [What's new in C# 6](../whats-new/csharp-6.md) article in the "What's new" section. + - title: Read only auto-properties enable readonly types durationInMinutes: 2 content: | Two enhancements to auto-property syntax make it easier to use auto-properties in more places: read-only auto-properties and auto-property initializers. Consider this small program: - ```csharp - using System; - - public class Person - { - public string FirstName { get; private set; } - public string LastName { get; private set; } - - public Person(string first, string last) - { - FirstName = first; - LastName = last; - } + [!code-csharp[Starter](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs)] - public override string ToString() - { - return FirstName + " " + LastName; - } - - public string AllCaps() - { - FirstName = FirstName.ToUpper(); - LastName = LastName.ToUpper(); - return ToString(); - } - } - - public class Program - { - public static void Main() - { - var p = new Person("Bill", "Wagner"); - Console.WriteLine("The name, in all caps " + p.AllCaps()); - Console.WriteLine("The name " + p); - } - } - ``` - - Click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be readonly. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a reaonly auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: + + Enter Focus mode, copy the preceding code into the C# interactive window. Then, click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be readonly. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a reaonly auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: ```csharp public string AllCaps() @@ -71,16 +37,7 @@ items: content: | New syntax in C# 6 enables you to use initializers for auto-properties. This becomes more important as classes grow new capabilities. Add a middle name property, and a new constructor that takes three strings to your `Person` class: - ```csharp - public string MiddleName { get; } = ""; - - public Person(string first, string middle, string last) - { - FirstName = first; - MiddleName = middle; - LastName = last; - } - ``` + [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#MiddleName)] The assignment on the `MiddleName` property is an initializer. It initializes the compiler-generated backing field for the middle name. @@ -100,9 +57,7 @@ items: content: | You may use a class' static methods throughout our code. Repeatedly typing the class name obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even those only is used. Modify the `using` statement as follows: - ```csharp - using static System.Console; - ``` + [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#UsingStatic)] The `static using` statement becomes more useful in larger programs that make extensive use of a single class with many static methods, like the `string` class or the class. @@ -111,38 +66,26 @@ items: content: | C# 6 contains new syntax for composing strings from a string and embedded expressions that are evaluated to produce other string values. You can change the `ToString` and `AllCaps` methods to use this syntax: - ```csharp - public override string ToString() => $"{FirstName} {LastName}"; - public string AllCaps() => $"{FirstName.ToUpper()} {LastName.ToUpper()}"; - ``` + [!code-csharp[StringInterpolation](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#StringInterpolation)] Instead of positional arguments between the `{` and `}`, you write C# expressions directly. You can do the same in the `Main` method. Replace the existing code with the following: - ```csharp - var p = new Person("Bill", "Wagner"); - Console.WriteLine($"The name, in all caps {p.AllCaps()}"); - Console.WriteLine($"The name is {p}"); - ``` + [!code-csharp[InterpolationMain](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#InterpolationMain)] You're not limited to a single variable in these expressions. Let's start with a new example and modify it to demonstrate. Paste the following code into the interactive window in the `Main` method: - ```csharp - var phrase = "the quick brown fox jumps over the lazy dog"; - var wordLength = from word in phrase.Split(" ") select word.Length; - var average = wordLength.Average(); - Console.WriteLine(average); - ``` - + [!code-csharp[Phrases](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#Phrases)] + You can remove the local variable `average` and perform that calculation as part of the interpolated string expression. Replace the last two lines with the following: ```csharp - Console.WriteLine($"The average word length is: {wordLength.Average()}"); + WriteLine($"The average word length is: {wordLength.Average()}"); ``` Running the preceding example, you would find that the output for `Average()` has more decimal places than you would like. The string interpolation syntax supports all the format strings available using earlier formatting methods. You specify the format string inside the braces. Add a `:` following the expression to format: ```csharp - Console.WriteLine($"The average word length is: {wordLength.Average():F2}"); + WriteLine($"The average word length is: {wordLength.Average():F2}"); ``` - title: Quick and easy null checks diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 6159bcd805774..16e74bfc74a56 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -8,7 +8,7 @@ ms.date: 12/12/2018 The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive, write more readable code. You can concentrate more on your features than on the constructs of the language. -The rest of this article provides an overview of each of these features, with a link to explore each feature. +The rest of this article provides an overview of each of these features, with a link to explore each feature. You can explore the features in an [interactive tutorial on C# 6](../tutorials/exploration/csharp-6.yml) in the tutorials section. ## Read-only auto-properties From ad26a51e03b754899277001fa929938d060022df Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:00:35 -0500 Subject: [PATCH 06/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index a5cbbe0ae9ea8..81d1e4868c69f 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -73,7 +73,7 @@ select new {p.ProductName, Price = p.UnitPrice}; ## Collection initializers -Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer you do not have to specify multiple calls to the `Add` method of the class in your source code; the compiler adds the calls. +Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer, you do not have to specify multiple calls to the `Add` method of the class in your source code; the compiler adds the calls. The following examples shows two simple collection initializers: From 2b60a04fda7374bc6a7d78a0b05ebe8340db2b2d Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:00:48 -0500 Subject: [PATCH 07/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index 81d1e4868c69f..793f25afb1561 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -75,7 +75,7 @@ select new {p.ProductName, Price = p.UnitPrice}; Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer, you do not have to specify multiple calls to the `Add` method of the class in your source code; the compiler adds the calls. -The following examples shows two simple collection initializers: +The following example shows two simple collection initializers: ```csharp List digits = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; From df0838373b399ea799b5a88c1c6f7e9cc74f8b5e Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:01:00 -0500 Subject: [PATCH 08/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 3ba4a8552498b..547f51aab3c7c 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -13,7 +13,7 @@ items: content: | This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can read about the features in the [What's new in C# 6](../whats-new/csharp-6.md) article in the "What's new" section. -- title: Read only auto-properties enable readonly types +- title: Read-only auto-properties enable read-only types durationInMinutes: 2 content: | Two enhancements to auto-property syntax make it easier to use auto-properties in more places: read-only auto-properties and auto-property initializers. Consider this small program: @@ -237,4 +237,4 @@ items: - content: | You've completed an exploration of the new features in C# 6. Now try them yourself in your applications. - \ No newline at end of file + From 367e630f39bc054fef14af43425b69281c9b2689 Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:01:51 -0500 Subject: [PATCH 09/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 547f51aab3c7c..b9af409573392 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -21,7 +21,7 @@ items: [!code-csharp[Starter](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs)] - Enter Focus mode, copy the preceding code into the C# interactive window. Then, click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be readonly. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a reaonly auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: + Enter Focus mode, copy the preceding code into the C# interactive window. Then, click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be read-only. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a read-only auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: ```csharp public string AllCaps() From ca5169cf2932d587bf8a347f645ce334d4dc36b9 Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:02:15 -0500 Subject: [PATCH 10/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index b9af409573392..b50d02e1c8d7f 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -52,7 +52,7 @@ items: Try the same with the `Caps` method. This is a small improvement, but when used wisely it creates much more readable code, especially for Data Transfer Objects (DTOs) and other types with minimal behavior. -- title: importing a single class +- title: Importing a single class durationInMinutes: 2 content: | You may use a class' static methods throughout our code. Repeatedly typing the class name obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even those only is used. Modify the `using` statement as follows: From da7d9c2182eed5d3fb9cbe0c07b826b3648bfc62 Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:02:24 -0500 Subject: [PATCH 11/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index b50d02e1c8d7f..e9a93fd5d8f1a 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -174,7 +174,7 @@ items: Beyond logging scenarios, exception filters can be most useful when a property of the exception determines what action to take. Consider looking inside an to see what the contained exceptions are. -- title: using nameof +- title: Using nameof durationInMinutes: 2 content: | The `nameof` operator returns the name of any variable or type. Try the following code in the interactive window to see how it works: From d54055baae5fd6414081ec87d6f657807cb7488c Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:02:34 -0500 Subject: [PATCH 12/46] Update docs/csharp/tutorials/index.md Co-Authored-By: BillWagner --- docs/csharp/tutorials/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/index.md b/docs/csharp/tutorials/index.md index 47fe2fdeb3a3d..6b732bb4d0053 100644 --- a/docs/csharp/tutorials/index.md +++ b/docs/csharp/tutorials/index.md @@ -62,7 +62,7 @@ on your machine. ## Explore new features in C# # -Try new features in [C# 6](../whats-new/csharp-6.md) in this [interactive exploration](exploration/csharp-6.yml) +Try new features in [C# 6](../whats-new/csharp-6.md) in this [interactive exploration](exploration/csharp-6.yml). ## General Tutorials From 7390df8d45d7c38380c9275618d73600e45eed32 Mon Sep 17 00:00:00 2001 From: Maira Wenzel Date: Mon, 24 Dec 2018 12:02:50 -0500 Subject: [PATCH 13/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index e9a93fd5d8f1a..e15654822f9a8 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -195,7 +195,7 @@ items: } ``` - The output matches the name of the variable or type. Even when you provided the fully-qualified type name (such as `System.String`) the `nameof` operator returns the unqualified name. This feature is most useful when you need to convert a parameter or property name to a string. Examples include throwing or , or implementing . + The output matches the name of the variable or type. Even when you provided the fully qualified type name (such as `System.String`) the `nameof` operator returns the unqualified name. This feature is most useful when you need to convert a parameter or property name to a string. Examples include throwing or , or implementing . - title: New object initialization syntax durationInMinutes: 2 From 7c5b144a74cf4738a1ad28b4ef0791dcea673a82 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 24 Dec 2018 12:17:49 -0500 Subject: [PATCH 14/46] respond to feedback --- docs/csharp/tutorials/exploration/csharp-6.yml | 11 ++++++++++- docs/csharp/whats-new/csharp-6.md | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index e15654822f9a8..cd608234e2301 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -44,7 +44,16 @@ items: - title: Expression-bodied members durationInMinutes: 2 content: | - Expression-bodied members provide a lightweight syntax for lightweight methods. The `Person` class has two great candidates. Replace the declaration of `ToString` with the following code: + Expression-bodied members provide a lightweight syntax for lightweight methods. The `Person` class has two great candidates. Look at the declaration of `ToString`: + + ```csharp + public overvide string ToString() + { + return FirstName + " " + LastName; + } + ``` + + Replace that declaration of `ToString` with the following code: ```csharp public override string ToString() => FirstName + " " + LastName; diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 16e74bfc74a56..8ebee0e446c6f 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -156,9 +156,9 @@ The implementation details for adding `await` support inside `catch` and `finall > [!NOTE] > This behavior is the reason it's recommended to write `catch` and `finally` clauses carefully, to avoid introducing new exceptions. -## Index initializers +## Initialize associative collections using indexers -*Index Initializers* is one of two features that make collection initializers more consistent with index usage. In earlier releases of C#, you could use *collection initializers* only with sequence style collections, including by adding braces around key and value pairs: +*Index Initializers* is one of two features that make collection initializers more consistent with index usage. In earlier releases of C#, you could use *collection initializers* with sequence style collections, including by adding braces around key and value pairs: [!code-csharp[ListInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#ListInitializer)] From 02413a6896a018de78edd7e980cc66257836e053 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 27 Dec 2018 10:10:19 -0500 Subject: [PATCH 15/46] fix tag name --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 8ebee0e446c6f..07bfb457cad23 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -160,7 +160,7 @@ The implementation details for adding `await` support inside `catch` and `finall *Index Initializers* is one of two features that make collection initializers more consistent with index usage. In earlier releases of C#, you could use *collection initializers* with sequence style collections, including by adding braces around key and value pairs: -[!code-csharp[ListInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#ListInitializer)] +[!code-csharp[ListInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#CollectionInitializer)] Now, you can use them with collections and other types where the accessible `Add` method accepts more than one argument. The new syntax supports assignment using an index into the collection: From 30f4451c1bf30206e1c8c7c84547b9ff33e51bd9 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 27 Dec 2018 10:43:23 -0500 Subject: [PATCH 16/46] fix build errors --- ...tialize-objects-by-using-an-object-initializer.md | 4 ++-- docs/csharp/tutorials/exploration/csharp-6.yml | 12 ++++++------ docs/csharp/whats-new/csharp-version-history.md | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md index 7797ee8cc29a1..4c078d4421a78 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md @@ -19,11 +19,11 @@ You must use an object initializer if you're defining an anonymous type. For mor The following example shows how to initialize a new `StudentName` type by using object initializers. This example sets properties in the `StudentName` type: -[!code-csharp-interactive[InitializerObjectExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToObjectInitializer.cs#HowToObjectInitializers)] +[!code-csharp-interactive[InitializerObjectExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToObjectInitializers.cs#HowToObjectInitializers)] Object initializers can be used to set indexers in an object. The following example defines a `BaseballTeam` class that uses an indexer to get and set players at different positions. The initializer can assign players, based on the abbreviation for the position, or the number used for each position baseball scorecards: -[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializer.cs#HOwToIndexInitializer)] +[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializers.cs#HOwToIndexInitializer)] ## See Also diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index cd608234e2301..1da0656b2a0c3 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -18,7 +18,7 @@ items: content: | Two enhancements to auto-property syntax make it easier to use auto-properties in more places: read-only auto-properties and auto-property initializers. Consider this small program: - [!code-csharp[Starter](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs)] + [!code-csharp[Starter](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs)] Enter Focus mode, copy the preceding code into the C# interactive window. Then, click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be read-only. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a read-only auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: @@ -37,7 +37,7 @@ items: content: | New syntax in C# 6 enables you to use initializers for auto-properties. This becomes more important as classes grow new capabilities. Add a middle name property, and a new constructor that takes three strings to your `Person` class: - [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#MiddleName)] + [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#MiddleName)] The assignment on the `MiddleName` property is an initializer. It initializes the compiler-generated backing field for the middle name. @@ -66,7 +66,7 @@ items: content: | You may use a class' static methods throughout our code. Repeatedly typing the class name obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even those only is used. Modify the `using` statement as follows: - [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#UsingStatic)] + [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#UsingStatic)] The `static using` statement becomes more useful in larger programs that make extensive use of a single class with many static methods, like the `string` class or the class. @@ -75,15 +75,15 @@ items: content: | C# 6 contains new syntax for composing strings from a string and embedded expressions that are evaluated to produce other string values. You can change the `ToString` and `AllCaps` methods to use this syntax: - [!code-csharp[StringInterpolation](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#StringInterpolation)] + [!code-csharp[StringInterpolation](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#StringInterpolation)] Instead of positional arguments between the `{` and `}`, you write C# expressions directly. You can do the same in the `Main` method. Replace the existing code with the following: - [!code-csharp[InterpolationMain](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#InterpolationMain)] + [!code-csharp[InterpolationMain](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#InterpolationMain)] You're not limited to a single variable in these expressions. Let's start with a new example and modify it to demonstrate. Paste the following code into the interactive window in the `Main` method: - [!code-csharp[Phrases](../../../../samples/csharp/tutorials/explorations/csharp6-starter/Program.cs#Phrases)] + [!code-csharp[Phrases](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#Phrases)] You can remove the local variable `average` and perform that calculation as part of the interpolated string expression. Replace the last two lines with the following: diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index d0974347339da..8aa139524d5ab 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -137,7 +137,7 @@ With versions 3.0 and 5.0, C# had added major new features in an object-oriented - [Null propagator](./csharp-6.md#null-conditional-operators) - [String interpolation](./csharp-6.md#string-interpolation) - [nameof operator](./csharp-6.md#the-nameof-expression) -- [Index initializers](csharp-6.md#index-initializers) +- [Index initializers](csharp-6.md#extension-add-methods-in-collection-initializers) Other new features include: From 4d61846e6feaceb1a4c4006d5b4d4b6b2ebe5bdc Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 27 Dec 2018 11:33:51 -0500 Subject: [PATCH 17/46] fix build warnings, part II --- .../how-to-initialize-objects-by-using-an-object-initializer.md | 2 +- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md index 4c078d4421a78..2dcae16b31c12 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md @@ -23,7 +23,7 @@ The following example shows how to initialize a new `StudentName` type by using Object initializers can be used to set indexers in an object. The following example defines a `BaseballTeam` class that uses an indexer to get and set players at different positions. The initializer can assign players, based on the abbreviation for the position, or the number used for each position baseball scorecards: -[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializers.cs#HOwToIndexInitializer)] +[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializer.cs#HOwToIndexInitializer)] ## See Also diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 1da0656b2a0c3..7b2ddbc70cb21 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -11,7 +11,7 @@ metadata: items: - durationInMinutes: 1 content: | - This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can read about the features in the [What's new in C# 6](../whats-new/csharp-6.md) article in the "What's new" section. + This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can read about the features in the [What's new in C# 6](../../whats-new/csharp-6.md) article in the "What's new" section. - title: Read-only auto-properties enable read-only types durationInMinutes: 2 From 69df291d1625ea4df87a3e7851499a582412db78 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:22:31 -0500 Subject: [PATCH 18/46] Update docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md Co-Authored-By: BillWagner --- ...-to-initialize-a-dictionary-with-a-collection-initializer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md index 03b2ae1ffb16b..7bcbdb8bfa510 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md @@ -8,7 +8,7 @@ ms.assetid: 25283922-f8ee-40dc-a639-fac30804ec71 --- # How to initialize a dictionary with a collection initializer (C# Programming Guide) -A contains a collection of key/value pairs. Its method takes two parameters, one for the key and one for the value. One way to initialize a , or any collection whose `Add` method takes multiple parameters, enclose each set of parameters in braces as shown in the following example. Another option is to use an index initializer, also shown in the following example. +A contains a collection of key/value pairs. Its method takes two parameters, one for the key and one for the value. One way to initialize a , or any collection whose `Add` method takes multiple parameters, is to enclose each set of parameters in braces as shown in the following example. Another option is to use an index initializer, also shown in the following example. ## Example From b237a786eac1f765fb442ef3b7af50f05eb42918 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:37:08 -0500 Subject: [PATCH 19/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index 793f25afb1561..935088efce719 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -73,7 +73,7 @@ select new {p.ProductName, Price = p.UnitPrice}; ## Collection initializers -Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer, you do not have to specify multiple calls to the `Add` method of the class in your source code; the compiler adds the calls. +Collection initializers let you specify one or more element initializers when you initialize a collection type that implements and has `Add` with the appropriate signature as an instance method or an extension method. The element initializers can be a simple value, an expression, or an object initializer. By using a collection initializer, you do not have to specify multiple calls; the compiler adds the calls automatically. The following example shows two simple collection initializers: From 7d15f2d72e37468dcf6878decc6ad42112e12e9d Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:37:39 -0500 Subject: [PATCH 20/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index 935088efce719..3b9f7f6a923a9 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -65,7 +65,7 @@ When this query is executed, the `productInfos` variable will contain a sequence foreach(var p in productInfos){...} ``` -Each object in the new anonymous type has two public properties which receive the same names as the properties or fields in the original object. You can also rename a field when you are creating an anonymous type; the following example renames the `UnitPrice` field to `Price`. +Each object in the new anonymous type has two public properties that receive the same names as the properties or fields in the original object. You can also rename a field when you are creating an anonymous type; the following example renames the `UnitPrice` field to `Price`. ```csharp select new {p.ProductName, Price = p.UnitPrice}; From bf1178374883f17e5048b5067db10b75959c4271 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:45:29 -0500 Subject: [PATCH 21/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index 3b9f7f6a923a9..c6c889c9376a0 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -98,7 +98,7 @@ The preceding sample generates code that calls the to add the three items into the dictionary. These two different ways to initialize associative collections have slightly different behavior because of the methods calls the compiler generates. Both variants work with the `Dictionary` class. Other types may only support one or the other based on their public API. +This initializer example calls to add the three items into the dictionary. These two different ways to initialize associative collections have slightly different behavior because of the method calls the compiler generates. Both variants work with the `Dictionary` class. Other types may only support one or the other based on their public API. ## Examples From 981d54bf0acbb36fff59d6bbdca4539acb39d4cf Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:46:20 -0500 Subject: [PATCH 22/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index c6c889c9376a0..f1d225313c2c8 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -106,7 +106,7 @@ The following example combines the concepts of object and collection initializer [!code-csharp-interactive[InitializerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#FullExample)] -Shown in the following example, an object which implements containing an `Add` method with multiple parameters allows for collection initializers with multiple elements per item in the list corresponding to the signature of the `Add` method. +The following example shows an object that implements and contains an `Add` method with multiple parameters, It uses a collection initializer with multiple elements per item in the list that correspond to the signature of the `Add` method. [!code-csharp-interactive[InitializerListExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#FullListExample)] From 998068713e773e7f63487b865e658ad6ae1db115 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:48:08 -0500 Subject: [PATCH 23/46] Update docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Co-Authored-By: BillWagner --- .../classes-and-structs/object-and-collection-initializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index f1d225313c2c8..7e49738554d12 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -110,7 +110,7 @@ The following example shows an object that implements Date: Fri, 4 Jan 2019 16:55:00 -0500 Subject: [PATCH 24/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 7b2ddbc70cb21..be0f6324ab307 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -47,7 +47,7 @@ items: Expression-bodied members provide a lightweight syntax for lightweight methods. The `Person` class has two great candidates. Look at the declaration of `ToString`: ```csharp - public overvide string ToString() + public override string ToString() { return FirstName + " " + LastName; } From 9f5dbf16ad82595eb3535b97d79684cc9e9a00c7 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:55:40 -0500 Subject: [PATCH 25/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index be0f6324ab307..731bca13c023a 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -64,7 +64,7 @@ items: - title: Importing a single class durationInMinutes: 2 content: | - You may use a class' static methods throughout our code. Repeatedly typing the class name obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even those only is used. Modify the `using` statement as follows: + If you repeatedly use a class' static methods throughout your code, including the class name each time obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even though only is used. Modify the `using` statement as follows: [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#UsingStatic)] From ed2af67eebc5cf08b45d92e4bc65acdcd6fae3b4 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 16:56:17 -0500 Subject: [PATCH 26/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 731bca13c023a..27f5a031ccabd 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -68,7 +68,7 @@ items: [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#UsingStatic)] - The `static using` statement becomes more useful in larger programs that make extensive use of a single class with many static methods, like the `string` class or the class. + The `static using` statement becomes more useful in larger programs that make extensive use of a single class with many static methods, like the [`string`](xref:System.String) class or the class. - title: A better string format durationInMinutes: 2 From 6e6f928a49cf058432fb93fba1a1941844863a40 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:03:12 -0500 Subject: [PATCH 27/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 27f5a031ccabd..08ffb1a3b002a 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -115,7 +115,7 @@ items: } ``` - It throws a . Change the `.` member access to the **null conditional operator**: + It throws a . Change the `.` member access operator to the **null conditional operator**: ```csharp Console.WriteLine(s?.Length); From a9a215b8af146a54f8ae5c57e68624fcaa576a41 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:03:50 -0500 Subject: [PATCH 28/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 08ffb1a3b002a..ad0109830cb3d 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -100,7 +100,7 @@ items: - title: Quick and easy null checks durationInMinutes: 2 content: | - The `?.` operator makes it easier to write logic that takes `null` values into account seamlessly, without extra `if` checks. To explore the feature, start by copying the following code into the interactive window to try it: + The `?.` (null conditional) operator makes it easier to write logic that takes `null` values into account seamlessly, without extra `if` checks. To explore the feature, start by copying the following code into the interactive window to try it: ```csharp using System; From 59497cab2299ade2368bee04be3357d02b8cbbb0 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:04:43 -0500 Subject: [PATCH 29/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index ad0109830cb3d..b16a36c22b69b 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -121,7 +121,7 @@ items: Console.WriteLine(s?.Length); ``` - After this change, there's no output. That's because the result of `s?.Length` is a `int?` whose value in this example is `null`. The `?.` returns `null` if its left operand is `null`. If the type of the right operand is a value type, the `?.` operator returns a nullable type for that type. In addition to `?.` you can use `?[]` for array or indexer access. Try the following code in the interactive window: + After this change, there's no output. That's because the result of `s?.Length` is an `int?` whose value in this example is `null`. The `?.` returns `null` if its left operand is `null`. If the type of the right operand is a value type, the `?.` operator returns a nullable type for that type. In addition to `?.` you can use `?[]` for array or indexer access. Try the following code in the interactive window: ```csharp char? c = s?[0]; From f37c97a6934c5f7bbf87e1f15cddd693a93cb10f Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:10:45 -0500 Subject: [PATCH 30/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index b16a36c22b69b..2089dee074e60 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -179,7 +179,7 @@ items: } ``` - You should have seen the message from the log method, followed by the default exception message. Just to experiment, change the `return false` statement to `return true` and run this again. Now, the exception is caught and the program runs to completion. + You should sen the message from the `LogException` method, followed by the default exception message. Just to experiment, change the `return false` statement to `return true` and run this again. Now, the exception is caught and the program runs to completion. Beyond logging scenarios, exception filters can be most useful when a property of the exception determines what action to take. Consider looking inside an to see what the contained exceptions are. From d0df7e30855748f2b57adf0ce90d2d431d4f1330 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:18:21 -0500 Subject: [PATCH 31/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 2089dee074e60..260930d6bc175 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -181,7 +181,7 @@ items: You should sen the message from the `LogException` method, followed by the default exception message. Just to experiment, change the `return false` statement to `return true` and run this again. Now, the exception is caught and the program runs to completion. - Beyond logging scenarios, exception filters can be most useful when a property of the exception determines what action to take. Consider looking inside an to see what the contained exceptions are. + Beyond logging scenarios, exception filters can be most useful when a property of the exception determines what action to take. For example, you can look inside an to see what the contained exceptions are and take some appropriate action depending on the specific exception. - title: Using nameof durationInMinutes: 2 From bb999e27c7e3590b1f8ae205e0f928203770df2e Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:19:54 -0500 Subject: [PATCH 32/46] Update docs/csharp/tutorials/exploration/csharp-6.yml Co-Authored-By: BillWagner --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 260930d6bc175..875ea257ae138 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -222,7 +222,7 @@ items: Console.WriteLine(messages[302]); ``` - You can extend this syntax to any class that implements and has a publicly accessible `Add` method. Try the following sample in the interactive window. It creates a `Path` class that implements `IEnumerable` and has a method to add points that takes three arguments. It also combines other techniques already demonstrated in this tutorial such as expression bodied members, and string interpolation. + You can extend this syntax to any class that implements and has a publicly accessible `Add` method. Try the following sample in the interactive window. It creates a `Path` class that implements `IEnumerable` and has a method to add points that takes three arguments. It also combines other techniques already demonstrated in this tutorial, such as expression-bodied members and string interpolation. In the `Main` method, you initialize a path by providing coordinates for the points. Those points are added to the collection through the `Add` method. From 71eed05a28d1f2c76aee57e543f0605f2f732edf Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:20:43 -0500 Subject: [PATCH 33/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 07bfb457cad23..d7b749cbb6c9e 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -6,7 +6,7 @@ ms.date: 12/12/2018 # What's New in C# 6 -The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive, write more readable code. You can concentrate more on your features than on the constructs of the language. +The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive and write more readable code. You can concentrate more on your features than on the constructs of the language. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can explore the features in an [interactive tutorial on C# 6](../tutorials/exploration/csharp-6.yml) in the tutorials section. From 893fb9aeceb2cd543876515843c74af02eeade02 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:22:20 -0500 Subject: [PATCH 34/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index d7b749cbb6c9e..69b989c17edd9 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -8,7 +8,7 @@ ms.date: 12/12/2018 The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive and write more readable code. You can concentrate more on your features than on the constructs of the language. -The rest of this article provides an overview of each of these features, with a link to explore each feature. You can explore the features in an [interactive tutorial on C# 6](../tutorials/exploration/csharp-6.yml) in the tutorials section. +The rest of this article provides an overview of each of these features, with a link to explore each feature. You can also explore the features in an [interactive tutorial on C# 6](../tutorials/exploration/csharp-6.yml) in the tutorials section. ## Read-only auto-properties From 2d4171ef8286af842af3640bba3775b46ec877a0 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:22:50 -0500 Subject: [PATCH 35/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 69b989c17edd9..bd2ceebf051ba 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -158,7 +158,7 @@ The implementation details for adding `await` support inside `catch` and `finall ## Initialize associative collections using indexers -*Index Initializers* is one of two features that make collection initializers more consistent with index usage. In earlier releases of C#, you could use *collection initializers* with sequence style collections, including by adding braces around key and value pairs: +*Index Initializers* is one of two features that make collection initializers more consistent with index usage. In earlier releases of C#, you could use *collection initializers* with sequence style collections, including , by adding braces around key and value pairs: [!code-csharp[ListInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#CollectionInitializer)] From 42903addecaed1c354c45029e4abaca44606db32 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:24:00 -0500 Subject: [PATCH 36/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index bd2ceebf051ba..0eb88cc574044 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -36,7 +36,7 @@ public class Student } ``` -This feature enables true language support for creating immutable types and using the more concise and convenient auto-property syntax. +This feature enables true language support for creating immutable types and uses the more concise and convenient auto-property syntax. If adding this syntax doesn't remove an accessible method, it's a [binary compatible change](version-update-considerations.md#binary-compatible-changes). From 8eee6ef4277015dafd344cc61ce4fc8e1c0e8cbd Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:25:04 -0500 Subject: [PATCH 37/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 0eb88cc574044..950ad453b464e 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -119,7 +119,7 @@ This example uses properties for the substituted expressions. You can use any ex The preceding line of code formats the value for `Grades.Average()` as a floating-point number with two decimal places. -Often you may need to format the string produced using a specific culture. You use the fact that the object produced by a string interpolation can be implicitly converted to . The instance contains the composite format string, and the results of evaluating the expressions before converting them to strings. Use the method to specify the culture when formatting a string. For example, the following example produces a string using German culture. (It uses the ',' character for the decimal separator, and the '.' character as the thousands separator.) +Often, you may need to format the string produced using a specific culture. You use the fact that the object produced by a string interpolation can be implicitly converted to . The instance contains the composite format string and the results of evaluating the expressions before converting them to strings. Use the method to specify the culture when formatting a string. The following example produces a string using the German (de-DE) culture. (By default, the German culture uses the ',' character for the decimal separator, and the '.' character as the thousands separator.) ```csharp FormattableString str = $"Average grade is {s.Grades.Average()}"; From 0a8058de6db47336eb9543a02da32e605650fd48 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:25:48 -0500 Subject: [PATCH 38/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 950ad453b464e..cc1616aced4da 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -46,7 +46,7 @@ If adding this syntax doesn't remove an accessible method, it's a [binary compat [!code-csharp[Initialization](../../../samples/snippets/csharp/new-in-6/newcode.cs#Initialization)] -The `Grades` member is initialized where it's declared. That makes it easier to perform the initialization exactly once. The initialization is part of the property declaration, making it easier to equate the storage allocation with public interface for `Student` objects. +The `Grades` member is initialized where it's declared. That makes it easier to perform the initialization exactly once. The initialization is part of the property declaration, making it easier to equate the storage allocation with the public interface for `Student` objects. ## Expression-bodied function members From 55986d428ba43897f2aa46be929ef7316f59f7b8 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:27:04 -0500 Subject: [PATCH 39/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index cc1616aced4da..08ce6fdba5e2d 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -87,7 +87,7 @@ The *null conditional operator* makes null checks much easier and fluid. Replace [!code-csharp[NullConditional](../../../samples/snippets/csharp/new-in-6/program.cs#NullConditional)] -In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it gets assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` when the `person` variable is `null`. Instead, it short-circuits and produces `null`. You can also use a null conditional operator for array or indexer access. Replace `[]` with `?[]` in the index expression. +In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it is assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` if the `person` variable is `null`. Instead, it short-circuits and returns `null`. You can also use a null conditional operator for array or indexer access. Replace `[]` with `?[]` in the index expression. This expression returns a `string`, regardless of the value of `person`. When the expression short-circuits, the `null` value returned is typed to match the full expression. From a2378d6eb58123e4195a8987f3d6c5dfff52c015 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:27:22 -0500 Subject: [PATCH 40/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 08ce6fdba5e2d..55a93e27390c3 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -126,7 +126,7 @@ FormattableString str = $"Average grade is {s.Grades.Average()}"; var gradeStr = str.ToString(new System.Globalization.CultureInfo("de-DE")); ``` -To get started with string interpolation, check the [String interpolation in C#](../tutorials/intro-to-csharp/interpolated-strings.yml) interactive tutorial, the [String interpolation](../language-reference/tokens/interpolated.md) article, and the [String interpolation in C#](../tutorials/string-interpolation.md) tutorial. +To get started with string interpolation, see the [String interpolation in C#](../tutorials/intro-to-csharp/interpolated-strings.yml) interactive tutorial, the [String interpolation](../language-reference/tokens/interpolated.md) article, and the [String interpolation in C#](../tutorials/string-interpolation.md) tutorial. ## Exception filters From 3f82608f954f3827a69e291d878724064528caa0 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:29:31 -0500 Subject: [PATCH 41/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 55a93e27390c3..bbf4a195c1c64 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -89,7 +89,7 @@ The *null conditional operator* makes null checks much easier and fluid. Replace In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it is assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` if the `person` variable is `null`. Instead, it short-circuits and returns `null`. You can also use a null conditional operator for array or indexer access. Replace `[]` with `?[]` in the index expression. -This expression returns a `string`, regardless of the value of `person`. When the expression short-circuits, the `null` value returned is typed to match the full expression. +The following expression returns a `string`, regardless of the value of `person`. When the expression short-circuits, the `null` value returned is typed to match the full expression. You often use this construct with the *null coalescing* operator to assign default values when one of the properties is `null`: From 426d574980f101b4baa6e5710adf8231e3c96e5c Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:32:29 -0500 Subject: [PATCH 42/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index bbf4a195c1c64..679e92f78035a 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -95,7 +95,7 @@ You often use this construct with the *null coalescing* operator to assign defau [!code-csharp[NullCoalescing](../../../samples/snippets/csharp/new-in-6/program.cs#NullCoalescing)] -You can also use `?.` to conditionally invoke methods. The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be `null`. You'll call the delegate's `Invoke` method using the `?.` operator to access the member. You can see an example in the +You can also use `?.` to conditionally invoke methods. The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be `null`. You can call the delegate's `Invoke` method using the `?.` operator to access the member. You can see an example in the [delegate patterns](../delegates-patterns.md#handling-null-delegates) article. The rules of the `?.` operator ensure that the left-hand side of the operator is evaluated only once. It enables many idioms, including the following example using event handlers: From 1e9a279a1060369a56c9275936890d8311f5ff83 Mon Sep 17 00:00:00 2001 From: Ron Petrusha Date: Fri, 4 Jan 2019 17:33:10 -0500 Subject: [PATCH 43/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 679e92f78035a..f89ad8d676498 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -109,7 +109,7 @@ Ensuring that the left side is evaluated only once also enables you to use any e ## String interpolation -With C# 6, the new [string interpolation](../language-reference/tokens/interpolated.md) feature enables you to embed the expressions in a string. Simply preface the string with `$`and use expressions between `{` and `}` instead of ordinals: +With C# 6, the new [string interpolation](../language-reference/tokens/interpolated.md) feature enables you to embed expressions in a string. Simply preface the string with `$`and use expressions between `{` and `}` instead of ordinals: [!code-csharp[stringInterpolation](../../../samples/snippets/csharp/new-in-6/newcode.cs#FullNameExpressionMember)] From 43ff86f603da2ce1b59f425c153c6504bd03ee2a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 4 Jan 2019 17:33:54 -0500 Subject: [PATCH 44/46] respond to feedback. --- ...ictionary-with-a-collection-initializer.md | 2 +- ...-objects-by-using-an-object-initializer.md | 2 +- .../object-and-collection-initializers.md | 6 +++- .../csharp/tutorials/exploration/csharp-6.yml | 30 +++++++++---------- docs/csharp/whats-new/csharp-6.md | 13 ++++---- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md index 7bcbdb8bfa510..8c5d8c2e7a6be 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer.md @@ -12,7 +12,7 @@ A contains a collection of key/ ## Example -In the following code example, a is initialized with instances of type `StudentName`. The first initialization uses the `Add` method with two arguments. The second uses the indexer method of the `Dictionary` class: +In the following code example, a is initialized with instances of type `StudentName`. The first initialization uses the `Add` method with two arguments. The compiler generates a call to `Add` for each of the pairs of `int` keys and `StudentName` values. The second uses a public read / write indexer method of the `Dictionary` class: [!code-csharp-interactive[InitializerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToDictionaryInitializer.cs#HowToDictionaryInitializer)] diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md index 2dcae16b31c12..f28ba149e83ca 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md @@ -23,7 +23,7 @@ The following example shows how to initialize a new `StudentName` type by using Object initializers can be used to set indexers in an object. The following example defines a `BaseballTeam` class that uses an indexer to get and set players at different positions. The initializer can assign players, based on the abbreviation for the position, or the number used for each position baseball scorecards: -[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializer.cs#HOwToIndexInitializer)] +[!code-csharp-interactive[InitializerIndexerExample](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/HowToIndexInitializer.cs#HowToIndexInitializer)] ## See Also diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index 793f25afb1561..d0910c305ee00 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -9,6 +9,10 @@ ms.assetid: c58f3db5-d7d4-4651-bd2d-5a3a97357f61 --- # Object and Collection Initializers (C# Programming Guide) +C# lets you instantiate an object or collection and perform member assignments in a single statement. + +## Object initializers + Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. The object initializer syntax enables you to specify arguments for a constructor or omit the arguments (and parentheses syntax). The following example shows how to use an object initializer with a named type, `Cat` and how to invoke the default constructor. Note the use of auto-implemented properties in the `Cat` class. For more information, see [Auto-Implemented Properties](auto-implemented-properties.md). [!code-csharp[ObjectInitializer1](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#CatDeclaration)] @@ -90,7 +94,7 @@ You can specify [null](../../language-reference/keywords/null.md) as an element [!code-csharp[ListInitializerNull](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#ListInitialerWithNull)] - You can specify indexed elements if the collection supports indexing. + You can specify indexed elements if the collection supports read / write indexing. [!code-csharp[DictionaryInitializer](../../../../samples/snippets/csharp/programming-guide/classes-and-structs/object-collection-initializers/BasicObjectInitializers.cs#DictionaryIndexerInitializer)] diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index 7b2ddbc70cb21..c13ab4866f1a0 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -11,7 +11,7 @@ metadata: items: - durationInMinutes: 1 content: | - This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can read about the features in the [What's new in C# 6](../../whats-new/csharp-6.md) article in the "What's new" section. + This tutorial lets you explore C# 6 interactively, using your browser to write C# and see the results of compiling and running your code. It contains a series of lessons that modify earlier C# practices to use newer, more concise C# 6 features. The rest of this article provides an overview of each of these features, with a link to explore each feature. - title: Read-only auto-properties enable read-only types durationInMinutes: 2 @@ -21,12 +21,12 @@ items: [!code-csharp[Starter](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs)] - Enter Focus mode, copy the preceding code into the C# interactive window. Then, click *Run* to see the error. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be read-only. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a read-only auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: + Enter Focus mode, copy the preceding code into the C# interactive window. Then, click *Run* to see what the code does. `AllCaps` has the undesirable side effect of modifying the property values along with returning the uppercase string. The author of the `Person` class intended the strings for `FirstName` and `LastName` to be read-only. With C# 6, you can make that intent clear. Remove the `private set` from both properties to create a read-only auto property. Click *Run* to see that the compiler spots the two locations where the `FirstName` and `LastName` properties are changed when they should not have been. You can change the `AllCaps` method to the following code to fix the compiler error: ```csharp public string AllCaps() { - return FirstName.ToUpper() + " " + LastName.ToUpper(); + return ToString().ToUpper(); } ``` @@ -37,7 +37,7 @@ items: content: | New syntax in C# 6 enables you to use initializers for auto-properties. This becomes more important as classes grow new capabilities. Add a middle name property, and a new constructor that takes three strings to your `Person` class: - [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#MiddleName)] + [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-finished/Program.cs#MiddleName)] The assignment on the `MiddleName` property is an initializer. It initializes the compiler-generated backing field for the middle name. @@ -66,7 +66,7 @@ items: content: | You may use a class' static methods throughout our code. Repeatedly typing the class name obscures the meaning of your code. The `Person` class currently imports the `System` namespace, even those only is used. Modify the `using` statement as follows: - [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#UsingStatic)] + [!code-csharp[MiddleName](../../../../samples/csharp/tutorials/exploration/csharp6-finished/Program.cs#UsingStatic)] The `static using` statement becomes more useful in larger programs that make extensive use of a single class with many static methods, like the `string` class or the class. @@ -75,15 +75,15 @@ items: content: | C# 6 contains new syntax for composing strings from a string and embedded expressions that are evaluated to produce other string values. You can change the `ToString` and `AllCaps` methods to use this syntax: - [!code-csharp[StringInterpolation](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#StringInterpolation)] + [!code-csharp[StringInterpolation](../../../../samples/csharp/tutorials/exploration/csharp6-finished/Program.cs#StringInterpolation)] Instead of positional arguments between the `{` and `}`, you write C# expressions directly. You can do the same in the `Main` method. Replace the existing code with the following: - [!code-csharp[InterpolationMain](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#InterpolationMain)] + [!code-csharp[InterpolationMain](../../../../samples/csharp/tutorials/exploration/csharp6-finished/Program.cs#InterpolationMain)] - You're not limited to a single variable in these expressions. Let's start with a new example and modify it to demonstrate. Paste the following code into the interactive window in the `Main` method: + You're not limited to a single variable in these expressions. Let's start with a new example and modify it to demonstrate other expressions you can use with string interpolation. Paste the following code into the interactive window in the `Main` method: - [!code-csharp[Phrases](../../../../samples/csharp/tutorials/exploration/csharp6-starter/Program.cs#Phrases)] + [!code-csharp[Phrases](../../../../samples/csharp/tutorials/exploration/csharp6-finished/Program.cs#Phrases)] You can remove the local variable `average` and perform that calculation as part of the interpolated string expression. Replace the last two lines with the following: @@ -91,7 +91,7 @@ items: WriteLine($"The average word length is: {wordLength.Average()}"); ``` - Running the preceding example, you would find that the output for `Average()` has more decimal places than you would like. The string interpolation syntax supports all the format strings available using earlier formatting methods. You specify the format string inside the braces. Add a `:` following the expression to format: + Running the preceding example, you would find that the output for `Average` has more decimal places than you would like. The string interpolation syntax supports all the format strings available using earlier formatting methods. You specify the format string inside the braces. Add a `:` following the expression to format: ```csharp WriteLine($"The average word length is: {wordLength.Average():F2}"); @@ -115,20 +115,20 @@ items: } ``` - It throws a . Change the `.` member access to the **null conditional operator**: + It throws a when you run the sample. Change the `.` member access to the **null conditional operator**: ```csharp Console.WriteLine(s?.Length); ``` - After this change, there's no output. That's because the result of `s?.Length` is a `int?` whose value in this example is `null`. The `?.` returns `null` if its left operand is `null`. If the type of the right operand is a value type, the `?.` operator returns a nullable type for that type. In addition to `?.` you can use `?[]` for array or indexer access. Try the following code in the interactive window: + After this change, there's no output. That's because the result of `s?.Length` is a `int?` where the result of `s.Length` is an `int`. In this example, `s?.Length` is `null`. The `?.` returns `null` if its left operand is `null`. If the type of the right operand is a value type, the `?.` operator returns a nullable type for that type. In addition to `?.` you can use `?[]` for array or indexer access. Try the following code in the interactive window: ```csharp char? c = s?[0]; Console.WriteLine(c.HasValue); ``` - The null conditional operator composes, making it easy to avoid nested if clauses to access members of members. For example, try the following code in the interactive window: + Multiple conditional operators can be combined into a single expression. A `null` left operand produces a `null` result, making it easy to avoid nested if clauses to access members of members. For example, try the following code in the interactive window: ```csharp string s = null; @@ -148,7 +148,7 @@ items: - title: Exception filers durationInMinutes: 2 content: | - Exception filters enable you to catch an exception based on some condition. A typical use is to create a filter method that logs exceptions and always returns false. Try the following code in the interactive window: It logs the exception type and message to the console. It returns false which indicates that the exception can't be handled. Try the program in the interactive window. + Exception filters enable you to catch an exception based on some condition. A typical use is to create a filter method that logs exceptions, but never handles those exceptions. An exception filter is a boolean expression that is `true` when the `catch` clause should be executed, and `false` when the exception should not be caught by the `catch` clause. Try the following code in the interactive window: It logs the exception type and message to the console. It returns false which indicates that the exception can't be handled. Try the program in the interactive window. ```csharp using System; @@ -162,8 +162,6 @@ items: string s = null; Console.WriteLine(s.Length); - bool? hasMore = s?.ToCharArray()?.GetEnumerator()?.MoveNext(); - Console.WriteLine(hasMore.HasValue); } catch (Exception e) when (LogException(e)) { } diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 07bfb457cad23..54753ef1c0aa7 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -6,7 +6,7 @@ ms.date: 12/12/2018 # What's New in C# 6 -The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive, write more readable code. You can concentrate more on your features than on the constructs of the language. +The 6.0 release of C# contains many features that improve productivity for developers. The overall effect of these features is that you write more concise code that is also more readable. The syntax contains less ceremony for many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll be more productive, write more readable code. You can concentrate more on your features than on the constructs of the language. The rest of this article provides an overview of each of these features, with a link to explore each feature. You can explore the features in an [interactive tutorial on C# 6](../tutorials/exploration/csharp-6.yml) in the tutorials section. @@ -66,7 +66,7 @@ The *using static* enhancement enables you to import the static methods of a sin [!code-csharp[UsingStaticMath](../../../samples/snippets/csharp/new-in-6/newcode.cs#UsingStaticMath)] -The does not contain any instance methods. You can also use `using static` to import a class' static methods for a class that has both static and instance methods. One of the most useful examples is : +The does not contain any instance methods. You can also use `using static` to import a class' static methods for a class that has both static and instance methods. One of the most useful examples is : [!code-csharp[UsingStatic](../../../samples/snippets/csharp/new-in-6/newcode.cs#UsingStatic)] @@ -89,14 +89,11 @@ The *null conditional operator* makes null checks much easier and fluid. Replace In the preceding example, the variable `first` is assigned `null` if the person object is `null`. Otherwise, it gets assigned the value of the `FirstName` property. Most importantly, the `?.` means that this line of code doesn't generate a `NullReferenceException` when the `person` variable is `null`. Instead, it short-circuits and produces `null`. You can also use a null conditional operator for array or indexer access. Replace `[]` with `?[]` in the index expression. -This expression returns a `string`, regardless of the value of `person`. When the expression short-circuits, the `null` value returned is typed to match the full expression. - -You often use this construct with the *null coalescing* operator to assign default values when one of the properties is `null`: +This expression returns a `string`, regardless of the value of `person`. You often use this construct with the *null coalescing* operator to assign default values when one of the properties is `null`. When the expression short-circuits, the `null` value returned is typed to match the full expression. [!code-csharp[NullCoalescing](../../../samples/snippets/csharp/new-in-6/program.cs#NullCoalescing)] -You can also use `?.` to conditionally invoke methods. The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be `null`. You'll call the delegate's `Invoke` method using the `?.` operator to access the member. You can see an example in the -[delegate patterns](../delegates-patterns.md#handling-null-delegates) article. +You can also use `?.` to conditionally invoke methods. The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be `null`. You'll call the delegate's `Invoke` method using the `?.` operator to access the member. You can see an example in the [delegate patterns](../delegates-patterns.md#handling-null-delegates) article. The rules of the `?.` operator ensure that the left-hand side of the operator is evaluated only once. It enables many idioms, including the following example using event handlers: @@ -147,7 +144,7 @@ Another use is with XAML-based applications that implement the `INotifyPropertyC ## Await in Catch and Finally blocks -C# 5 had several limitations around where you could place `await` expressions. You can now use `await` in `catch` or `finally` expressions. With C# 6, you can also await in catch expressions. This is most often used with logging scenarios: +C# 5 had several limitations around where you could place `await` expressions. With C# 6, you can now use `await` in `catch` or `finally` expressions. This is most often used with logging scenarios: [!code-csharp[AwaitFinally](../../../samples/snippets/csharp/new-in-6/NetworkClient.cs#AwaitFinally)] From 953a212ef024a03afaadac558df4ad3ea60ec3dd Mon Sep 17 00:00:00 2001 From: Petr Kulikov Date: Fri, 4 Jan 2019 17:44:32 -0500 Subject: [PATCH 45/46] Update docs/csharp/whats-new/csharp-6.md Co-Authored-By: BillWagner --- docs/csharp/whats-new/csharp-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-6.md b/docs/csharp/whats-new/csharp-6.md index 87f410fd93e2e..d9a68201aa4ac 100644 --- a/docs/csharp/whats-new/csharp-6.md +++ b/docs/csharp/whats-new/csharp-6.md @@ -159,7 +159,7 @@ The implementation details for adding `await` support inside `catch` and `finall [!code-csharp[ListInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#CollectionInitializer)] -Now, you can use them with collections and other types where the accessible `Add` method accepts more than one argument. The new syntax supports assignment using an index into the collection: +You can use them with collections and other types where the accessible `Add` method accepts more than one argument. The new syntax supports assignment using an index into the collection: [!code-csharp[DictionaryInitializer](../../../samples/snippets/csharp/new-in-6/initializers.cs#DictionaryInitializer)] From 0e78c9b73610efa37c5345426fdd50fde686c2cd Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 4 Jan 2019 17:45:08 -0500 Subject: [PATCH 46/46] respond to feedback. --- docs/csharp/tutorials/exploration/csharp-6.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/exploration/csharp-6.yml b/docs/csharp/tutorials/exploration/csharp-6.yml index ef45e2f689d7f..0a56ba0bd2ac0 100644 --- a/docs/csharp/tutorials/exploration/csharp-6.yml +++ b/docs/csharp/tutorials/exploration/csharp-6.yml @@ -202,7 +202,7 @@ items: } ``` - The output matches the name of the variable or type. Even when you provided the fully qualified type name (such as `System.String`) the `nameof` operator returns the unqualified name. This feature is most useful when you need to convert a parameter or property name to a string. Examples include throwing or , or implementing . + The output matches the name of the variable or type. Even when you provided the fully qualified type name (such as `System.String`) the `nameof` operator returns the unqualified name. This feature is most useful when you need to convert a parameter or property name to a string. Examples include capturing the name of an argument for throwing a or , or capturing the name of a changed property when implementing . - title: New object initialization syntax durationInMinutes: 2