From ab7728e6369be27c769489041a7b7ddd50f8060e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 29 Aug 2022 17:01:20 -0400 Subject: [PATCH 01/16] Split struct article into two articles. Update all links to sections that have moved. --- .../builtin-types/ref-struct.md | 39 +++++++++++++++++++ .../builtin-types/struct.md | 34 +++------------- .../csharp/language-reference/keywords/ref.md | 2 +- docs/csharp/toc.yml | 5 ++- docs/csharp/write-safe-efficient-code.md | 2 +- docs/standard/io/buffers.md | 2 +- .../serialization/system-text-json-how-to.md | 2 +- ...n-use-dom-utf8jsonreader-utf8jsonwriter.md | 2 +- 8 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 docs/csharp/language-reference/builtin-types/ref-struct.md diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md new file mode 100644 index 0000000000000..1a93d64519526 --- /dev/null +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -0,0 +1,39 @@ +--- +title: "Ref Struct types - C# reference" +description: Learn about the ref struct type in C# +ms.date: 09/02/2022 +--- +# `ref` Structure types (C# reference) + +Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a structure type. Instances of a `ref` struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref` struct types as follows: + +- A `ref` struct can't be the element type of an array. +- A `ref` struct can't be a declared type of a field of a class or a non-`ref` struct. +- A `ref` struct can't implement interfaces. +- A `ref` struct can't be boxed to or . +- A `ref` struct can't be a type argument. +- A `ref` struct variable can't be captured by a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md). +- A `ref` struct variable can't be used in an [`async`](../keywords/async.md) method. However, you can use `ref` struct variables in synchronous methods, for example, in methods that return or . +- A `ref` struct variable can't be used in [iterators](../../iterators.md). + +Beginning with C# 8.0, you can define a disposable `ref` struct. To do that, ensure that a `ref` struct fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type. + +Beginning with C# 11.0, a `ref struct` may contain `ref` fields. + +Typically, you define a `ref` struct type when you need a type that also includes data members of `ref` struct types: + +:::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetRefStruct"::: + +To declare a `ref` struct as `readonly`, combine the `readonly` and `ref` modifiers in the type declaration (the `readonly` modifier must come before the `ref` modifier): + +:::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetReadonlyRef"::: + +In .NET, examples of a `ref` struct are and . + +## C# language specification + +For more information, see the [Structs](~/_csharpstandard/standard/structs.md) section of the [C# language specification](~/_csharpstandard/standard/README.md). + +For more information about features introduced in C# 7.2 and later, see the following feature proposal notes: + +- [Compile-time safety for ref-like types](~/_csharplang/proposals/csharp-7.2/span-safety.md) diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index eebf265b3abe2..75e2bbc4577bb 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -1,7 +1,7 @@ --- title: "Structure types - C# reference" description: Learn about the struct type in C# -ms.date: 12/16/2021 +ms.date: 09/02/2022 f1_keywords: - "struct_CSharpKeyword" helpviewer_keywords: @@ -16,6 +16,8 @@ A *structure type* (or *struct type*) is a [value type](value-types.md) that can [!code-csharp[struct example](snippets/shared/StructType.cs#StructExample)] +`ref struct` types and `readonly ref struct` types are covered in the article on [`ref struct` types](ref-struct.md). + Structure types have *value semantics*. That is, a variable of a structure type contains an instance of the type. By default, variable values are copied on assignment, passing an argument to a method, and returning a method result. For structure-type variables, an instance of the type is copied. For more information, see [Value types](value-types.md). Typically, you use structure types to design small data-centric types that provide little or no behavior. For example, .NET uses structure types to represent a number (both [integer](integral-numeric-types.md) and [real](floating-point-numeric-types.md)), a [Boolean value](bool.md), a [Unicode character](char.md), a [time instance](xref:System.DateTime). If you're focused on the behavior of a type, consider defining a [class](../keywords/class.md). Class types have *reference semantics*. That is, a variable of a class type contains a reference to an instance of the type, not the instance itself. @@ -79,7 +81,7 @@ Beginning with C# 10, you can use the [`with` expression](../operators/with-expr ## `record` struct -Beginning with C# 10, you can define record structure types. Record types provide built-in functionality for encapsulating data. You can define both `record struct` and `readonly record struct` types. A record struct can't be a [`ref` struct](#ref-struct). For more information and examples, see [Records](record.md). +Beginning with C# 10, you can define record structure types. Record types provide built-in functionality for encapsulating data. You can define both `record struct` and `readonly record struct` types. A record struct can't be a [`ref` struct](ref-struct.md). For more information and examples, see [Records](record.md). ## Struct initialization and default values @@ -127,38 +129,13 @@ Structs have most of the capabilities of a [class](../keywords/class.md) type. T When you pass a structure-type variable to a method as an argument or return a structure-type value from a method, the whole instance of a structure type is copied. Pass by value can affect the performance of your code in high-performance scenarios that involve large structure types. You can avoid value copying by passing a structure-type variable by reference. Use the [`ref`](../keywords/ref.md#passing-an-argument-by-reference), [`out`](../keywords/out-parameter-modifier.md), or [`in`](../keywords/in-parameter-modifier.md) method parameter modifiers to indicate that an argument must be passed by reference. Use [ref returns](../../programming-guide/classes-and-structs/ref-returns.md) to return a method result by reference. For more information, see [Write safe and efficient C# code](../../write-safe-efficient-code.md). -## `ref` struct - -Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a structure type. Instances of a `ref` struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref` struct types as follows: - -- A `ref` struct can't be the element type of an array. -- A `ref` struct can't be a declared type of a field of a class or a non-`ref` struct. -- A `ref` struct can't implement interfaces. -- A `ref` struct can't be boxed to or . -- A `ref` struct can't be a type argument. -- A `ref` struct variable can't be captured by a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md). -- A `ref` struct variable can't be used in an [`async`](../keywords/async.md) method. However, you can use `ref` struct variables in synchronous methods, for example, in methods that return or . -- A `ref` struct variable can't be used in [iterators](../../iterators.md). - -Beginning with C# 8.0, you can define a disposable `ref` struct. To do that, ensure that a `ref` struct fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type. - -Typically, you define a `ref` struct type when you need a type that also includes data members of `ref` struct types: - -[!code-csharp[ref struct](snippets/shared/StructType.cs#RefStruct)] - -To declare a `ref` struct as [`readonly`](#readonly-struct), combine the `readonly` and `ref` modifiers in the type declaration (the `readonly` modifier must come before the `ref` modifier): - -[!code-csharp[readonly ref struct](snippets/shared/StructType.cs#ReadonlyRef)] - -In .NET, examples of a `ref` struct are and . - ## struct constraint You also use the `struct` keyword in the [`struct` constraint](../../programming-guide/generics/constraints-on-type-parameters.md) to specify that a type parameter is a non-nullable value type. Both structure and [enumeration](enum.md) types satisfy the `struct` constraint. ## Conversions -For any structure type (except [`ref` struct](#ref-struct) types), there exist [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the and types. There exist also boxing and unboxing conversions between a structure type and any interface that it implements. +For any structure type (except [`ref` struct](ref-struct.md) types), there exist [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the and types. There exist also boxing and unboxing conversions between a structure type and any interface that it implements. ## C# language specification @@ -168,7 +145,6 @@ For more information about features introduced in C# 7.2 and later, see the foll - [Readonly structs](~/_csharplang/proposals/csharp-7.2/readonly-ref.md#readonly-structs) - [Readonly instance members](~/_csharplang/proposals/csharp-8.0/readonly-instance-members.md) -- [Compile-time safety for ref-like types](~/_csharplang/proposals/csharp-7.2/span-safety.md) - [Parameterless struct constructors](~/_csharplang/proposals/csharp-10.0/parameterless-struct-constructors.md) - [Allow `with` expression on structs](~/_csharplang/proposals/csharp-10.0/record-structs.md#allow-with-expression-on-structs) - [Record structs](~/_csharplang/proposals/csharp-10.0/record-structs.md) diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index b662926143bf4..0ca83ba28c041 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -15,7 +15,7 @@ The `ref` keyword indicates that a value is passed by reference. It is used in f - In a method signature and in a method call, to pass an argument to a method by reference. For more information, see [Passing an argument by reference](#passing-an-argument-by-reference). - In a method signature, to return a value to the caller by reference. For more information, see [Reference return values](#reference-return-values). - In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify. Or to indicate that a local variable accesses another value by reference. For more information, see [Ref locals](#ref-locals). -- In a `struct` declaration, to declare a `ref struct` or a `readonly ref struct`. For more information, see the [`ref` struct](../builtin-types/struct.md#ref-struct) section of the [Structure types](../builtin-types/struct.md) article. +- In a `struct` declaration, to declare a `ref struct` or a `readonly ref struct`. For more information, see the [`ref` struct](../builtin-types/ref-struct.md) section of the [Structure types](../builtin-types/struct.md) article. ## Passing an argument by reference diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index b9abbb9dd5e3e..319334d201500 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -882,9 +882,12 @@ items: - name: Enumeration types href: language-reference/builtin-types/enum.md displayName: "enum, bit flags, bit field" - - name: Structure types + - name: Struct types href: language-reference/builtin-types/struct.md displayName: "struct type, readonly struct, ref struct, readonly ref struct" + - name: Ref struct types + href: language-reference/builtin-types/ref-struct.md + displayName: "ref struct, readonly ref struct" - name: Tuple types href: language-reference/builtin-types/value-tuples.md displayName: "value tuples, ValueTuple" diff --git a/docs/csharp/write-safe-efficient-code.md b/docs/csharp/write-safe-efficient-code.md index da51d67380c93..51ae4d3e09d0d 100644 --- a/docs/csharp/write-safe-efficient-code.md +++ b/docs/csharp/write-safe-efficient-code.md @@ -263,7 +263,7 @@ You can see an example program that demonstrates the performance differences usi ## Use `ref struct` types -Use a [`ref struct`](language-reference/builtin-types/struct.md#ref-struct) or a `readonly ref struct`, such as or , to work with blocks of memory as a sequence of bytes. The memory used by the span is constrained to a single stack frame. This restriction enables the compiler to make several optimizations. The primary motivation for this feature was and related structures. You'll achieve performance improvements from these enhancements by using new and updated .NET APIs that make use of the type. +Use a [`ref struct`](language-reference/builtin-types/ref-struct.md) or a `readonly ref struct`, such as or , to work with blocks of memory as a sequence of bytes. The memory used by the span is constrained to a single stack frame. This restriction enables the compiler to make several optimizations. The primary motivation for this feature was and related structures. You'll achieve performance improvements from these enhancements by using new and updated .NET APIs that make use of the type. Declaring a struct as `readonly ref` combines the benefits and restrictions of `ref struct` and `readonly struct` declarations. The memory used by the readonly span is restricted to a single stack frame, and the memory used by the readonly span can't be modified. diff --git a/docs/standard/io/buffers.md b/docs/standard/io/buffers.md index 70e78e7fcfb6c..8bfecce04ae4d 100644 --- a/docs/standard/io/buffers.md +++ b/docs/standard/io/buffers.md @@ -186,5 +186,5 @@ The following example parses a 4-byte big-endian integer length from the start o ### SequenceReader\ common problems - Because `SequenceReader` is a mutable struct, it should always be passed by [reference](../../csharp/language-reference/keywords/ref.md). -- `SequenceReader` is a [ref struct](../../csharp/language-reference/builtin-types/struct.md#ref-struct) so it can only be used in synchronous methods and can't be stored in fields. For more information, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). +- `SequenceReader` is a [ref struct](../../csharp/language-reference/builtin-types/ref-struct.md) so it can only be used in synchronous methods and can't be stored in fields. For more information, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). - `SequenceReader` is optimized for use as a forward-only reader. `Rewind` is intended for small backups that can't be addressed utilizing other `Read`, `Peek`, and `IsNext` APIs. diff --git a/docs/standard/serialization/system-text-json-how-to.md b/docs/standard/serialization/system-text-json-how-to.md index 8efffde6e96c8..3b000871f6934 100644 --- a/docs/standard/serialization/system-text-json-how-to.md +++ b/docs/standard/serialization/system-text-json-how-to.md @@ -42,7 +42,7 @@ The code samples in this article: ## Visual Basic support -Parts of System.Text.Json use [ref structs](../../csharp/language-reference/builtin-types/struct.md#ref-struct), which are not supported by Visual Basic. If you try to use System.Text.Json ref struct APIs with Visual Basic you get BC40000 compiler errors. The error message indicates that the problem is an obsolete API, but the actual issue is lack of ref struct support in the compiler. The following parts of System.Text.Json aren't usable from Visual Basic: +Parts of System.Text.Json use [ref structs](../../csharp/language-reference/builtin-types/ref-struct.md), which are not supported by Visual Basic. If you try to use System.Text.Json ref struct APIs with Visual Basic you get BC40000 compiler errors. The error message indicates that the problem is an obsolete API, but the actual issue is lack of ref struct support in the compiler. The following parts of System.Text.Json aren't usable from Visual Basic: * The class. Since the method takes a `Utf8JsonReader` parameter, this limitation means you can't use Visual Basic to write custom converters. A workaround for this is to implement custom converters in a C# library assembly, and reference that assembly from your VB project. This assumes that all you do in Visual Basic is register the converters into the serializer. You can't call the `Read` methods of the converters from Visual Basic code. * Overloads of other APIs that include a type. Most methods include overloads that use `String` instead of `ReadOnlySpan`. diff --git a/docs/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter.md b/docs/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter.md index ed93b63631d5c..00a596157436a 100644 --- a/docs/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter.md +++ b/docs/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter.md @@ -304,7 +304,7 @@ The preceding example sets no limit to how large the buffer can grow. If the tok ### Utf8JsonReader is a ref struct -Because the `Utf8JsonReader` type is a *ref struct*, it has [certain limitations](../../csharp/language-reference/builtin-types/struct.md#ref-struct). For example, it can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, this type must be a `ref struct` since it needs to cache the input [ReadOnlySpan\](xref:System.ReadOnlySpan%601), which itself is a ref struct. In addition, this type is mutable since it holds state. Therefore, **pass it by reference** rather than by value. Passing it by value would result in a struct copy and the state changes would not be visible to the caller. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). +Because the `Utf8JsonReader` type is a *ref struct*, it has [certain limitations](../../csharp/language-reference/builtin-types/ref-struct.md). For example, it can't be stored as a field on a class or struct other than a ref struct. To achieve high performance, this type must be a `ref struct` since it needs to cache the input [ReadOnlySpan\](xref:System.ReadOnlySpan%601), which itself is a ref struct. In addition, this type is mutable since it holds state. Therefore, **pass it by reference** rather than by value. Passing it by value would result in a struct copy and the state changes would not be visible to the caller. For more information about how to use ref structs, see [Write safe and efficient C# code](../../csharp/write-safe-efficient-code.md). ### Read UTF-8 text From 2c11c2420c9ecb2c8f65aa72a4b0c4aa2b79c363 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 30 Aug 2022 15:47:42 -0400 Subject: [PATCH 02/16] Move pass by ref / value to language reference Move the pass by reference and pass by value sections of the programming guide to the C# language reference. --- .openpublishing.redirection.csharp.json | 16 ++++ docs/csharp/how-to/index.md | 1 - .../compiler-messages/cs0269.md | 2 +- .../keywords/method-parameters.md | 95 +++++++++++++++++-- .../csharp/language-reference/keywords/ref.md | 3 +- .../keywords/snippets/PassParameters.cs} | 10 +- .../keywords/snippets/Program.cs | 2 + docs/csharp/methods.md | 2 +- docs/csharp/misc/cs0177.md | 2 +- docs/csharp/misc/cs0199.md | 2 +- docs/csharp/misc/cs0206.md | 2 +- docs/csharp/misc/cs0241.md | 2 +- ...-struct-and-passing-a-class-to-a-method.md | 32 ------- .../classes-and-structs/methods.md | 6 +- .../classes-and-structs/passing-parameters.md | 34 ------- .../passing-reference-type-parameters.md | 47 --------- .../passing-value-type-parameters.md | 44 --------- docs/csharp/toc.yml | 10 -- 18 files changed, 121 insertions(+), 191 deletions(-) rename docs/csharp/{programming-guide/classes-and-structs/snippets/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method/Program.cs => language-reference/keywords/snippets/PassParameters.cs} (86%) delete mode 100644 docs/csharp/programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md delete mode 100644 docs/csharp/programming-guide/classes-and-structs/passing-parameters.md delete mode 100644 docs/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters.md delete mode 100644 docs/csharp/programming-guide/classes-and-structs/passing-value-type-parameters.md diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index d68ef0af85f7d..b008e5da2599a 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -1056,6 +1056,10 @@ "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/how-to-access-a-collection-class-with-foreach.md", "redirect_url": "/dotnet/csharp/language-reference/statements/iteration-statements" }, + { + "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md", + "redirect_url": "/dotnet/csharp/language-reference/keywords/method-parameters" + }, { "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/index.md", "redirect_url": "/dotnet/csharp/fundamentals/object-oriented" @@ -1068,6 +1072,18 @@ "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/objects.md", "redirect_url": "/dotnet/csharp/fundamentals/object-oriented/objects" }, + { + "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/passing-parameters.md", + "redirect_url": "/dotnet/csharp/language-reference/keywords/method-parameters" + }, + { + "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters.md", + "redirect_url": "/dotnet/csharp/language-reference/keywords/method-parameters" + }, + { + "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/passing-value-type-parameters.md", + "redirect_url": "/dotnet/csharp/language-reference/keywords/method-parameters" + }, { "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/polymorphism.md", "redirect_url": "/dotnet/csharp/fundamentals/object-oriented/polymorphism" diff --git a/docs/csharp/how-to/index.md b/docs/csharp/how-to/index.md index c3c462dba93f7..d54d78228d68e 100644 --- a/docs/csharp/how-to/index.md +++ b/docs/csharp/how-to/index.md @@ -14,7 +14,6 @@ In the How to section of the C# Guide, you can find quick answers to common ques There are several tips and tricks that are common C# developer practices: - [Initialize objects using an object initializer](../programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md). -- [Learn the differences between passing a struct and a class to a method](../programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md). - [Use operator overloading](../language-reference/operators/operator-overloading.md). - [Implement and call a custom extension method](../programming-guide/classes-and-structs/how-to-implement-and-call-a-custom-extension-method.md). - [Create a new method for an `enum` type using extension methods](../programming-guide/classes-and-structs/how-to-create-a-new-method-for-an-enumeration.md). diff --git a/docs/csharp/language-reference/compiler-messages/cs0269.md b/docs/csharp/language-reference/compiler-messages/cs0269.md index 5686602de51c3..7c3668b569b7d 100644 --- a/docs/csharp/language-reference/compiler-messages/cs0269.md +++ b/docs/csharp/language-reference/compiler-messages/cs0269.md @@ -12,7 +12,7 @@ ms.assetid: 7ef8374c-6f82-4096-bf4b-70080d4ddf88 Use of unassigned out parameter 'parameter' - The compiler could not verify that the out parameter was assigned a value before it was used; its value may be undefined when assigned. Be sure to assign a value to `out` parameters in the called method before accessing the value. If you need to use the value of the variable passed in, use a `ref` parameter instead. For more information, see [Passing Parameters](../../programming-guide/classes-and-structs/passing-parameters.md). + The compiler could not verify that the out parameter was assigned a value before it was used; its value may be undefined when assigned. Be sure to assign a value to `out` parameters in the called method before accessing the value. If you need to use the value of the variable passed in, use a `ref` parameter instead. For more information, see [Method Parameters](../keywords/method-parameters.md). ## Example 1 diff --git a/docs/csharp/language-reference/keywords/method-parameters.md b/docs/csharp/language-reference/keywords/method-parameters.md index d02d3faf52e78..10dc21742d414 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -1,7 +1,7 @@ --- description: "Method Parameters - C# Reference" title: "Method Parameters - C# Reference" -ms.date: 07/20/2015 +ms.date: 08/30/2022 helpviewer_keywords: - "methods [C#], parameters" - "method parameters [C#]" @@ -10,20 +10,95 @@ ms.assetid: 680e39ff-775b-48b0-9f47-4186a5bfc4a1 --- # Method Parameters (C# Reference) -Parameters declared for a method without [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md), are passed to the called method by value. That value can be changed in the method, but the changed value will not be retained when control passes back to the calling procedure. By using a method parameter keyword, you can change this behavior. - - This section describes the keywords you can use when declaring method parameters: - +In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment. To pass a parameter by reference with the intent of changing the value, use the `ref`, or `out` keyword. To pass by reference with the intent of avoiding copying but not changing the value, use the `in` modifier. For simplicity, only the `ref` keyword is used in the examples in this topic. For more information about the difference between `in`, `ref`, and `out`, see [in](in-parameter-modifier.md), [ref](ref.md), and [out](out-parameter-modifier.md). + +The following example illustrates the difference between value and reference parameters. + +[!code-csharp[csProgGuideParameters#10](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#10)] + +## Passing Value-Type Parameters + +A [value-type](../builtin-types/value-types.md) variable contains its data directly as opposed to a [reference-type](reference-types.md) variable, which contains a reference to its data. Passing a value-type variable to a method by value means passing a copy of the variable to the method. Any changes to the parameter that take place inside the method have no effect on the original data stored in the argument variable. If you want the called method to change the value of the argument, you must pass it by reference, using the [ref](ref.md) or [out](out-parameter-modifier.md) keyword. You may also use the [in](in-parameter-modifier.md) keyword to pass a value parameter by reference to avoid the copy while guaranteeing that the value will not be changed. For simplicity, the following examples use `ref`. + +### Passing Value Types by Value + +The following example demonstrates passing value-type parameters by value. The variable `n` is passed by value to the method `SquareIt`. Any changes that take place inside the method have no effect on the original value of the variable. + +[!code-csharp[csProgGuideParameters#3](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#3)] + +The variable `n` is a value type. It contains its data, the value `5`. When `SquareIt` is invoked, the contents of `n` are copied into the parameter `x`, which is squared inside the method. In `Main`, however, the value of `n` is the same after calling the `SquareIt` method as it was before. The change that takes place inside the method only affects the local variable `x`. + +### Passing Value Types by Reference + +The following example is the same as the previous example, except that the argument is passed as a `ref` parameter. The value of the underlying argument, `n`, is changed when `x` is changed in the method. + +[!code-csharp[csProgGuideParameters#4](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#4)] + +In this example, it is not the value of `n` that is passed; rather, a reference to `n` is passed. The parameter `x` is not an [int](../builtin-types/integral-numeric-types.md); it is a reference to an `int`, in this case, a reference to `n`. Therefore, when `x` is squared inside the method, what actually is squared is what `x` refers to, `n`. + +### Swapping Value Types + +A common example of changing the values of arguments is a swap method, where you pass two variables to the method, and the method swaps their contents. You must pass the arguments to the swap method by reference. Otherwise, you swap local copies of the parameters inside the method, and no change occurs in the calling method. The following example swaps integer values. + +[!code-csharp[csProgGuideParameters#5](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#5)] + +When you call the `SwapByRef` method, use the `ref` keyword in the call, as shown in the following example. + +[!code-csharp[csProgGuideParameters#6](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#6)] + +## Passing Reference-Type Parameters + +A variable of a [reference type](reference-types.md) does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data belonging to the referenced object, such as the value of a class member. However, you cannot change the value of the reference itself; for example, you cannot use the same reference to allocate memory for a new object and have it persist outside the method. To do that, pass the parameter using the [ref](ref.md) or [out](out-parameter-modifier.md) keyword. For simplicity, the following examples use `ref`. + +### Passing Reference Types by Value + +The following example demonstrates passing a reference-type parameter, `arr`, by value, to a method, `Change`. Because the parameter is a reference to `arr`, it is possible to change the values of the array elements. However, the attempt to reassign the parameter to a different memory location only works inside the method and does not affect the original variable, `arr`. + +[!code-csharp[csProgGuideParameters#7](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#7)] + +In the preceding example, the array, `arr`, which is a reference type, is passed to the method without the `ref` parameter. In such a case, a copy of the reference, which points to `arr`, is passed to the method. The output shows that it is possible for the method to change the contents of an array element, in this case from `1` to `888`. However, allocating a new portion of memory by using the [new](../operators/new-operator.md) operator inside the `Change` method makes the variable `pArray` reference a new array. Thus, any changes after that will not affect the original array, `arr`, which is created inside `Main`. In fact, two arrays are created in this example, one inside `Main` and one inside the `Change` method. + +### Passing Reference Types by Reference + +The following example is the same as the previous example, except that the `ref` keyword is added to the method header and call. Any changes that take place in the method affect the original variable in the calling program. + +[!code-csharp[csProgGuideParameters#8](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#8)] + +All of the changes that take place inside the method affect the original array in `Main`. In fact, the original array is reallocated using the `new` operator. Thus, after calling the `Change` method, any reference to `arr` points to the five-element array, which is created in the `Change` method. + +### Swapping Two Strings + +Swapping strings is a good example of passing reference-type parameters by reference. In the example, two strings, `str1` and `str2`, are initialized in `Main` and passed to the `SwapStrings` method as parameters modified by the `ref` keyword. The two strings are swapped inside the method and inside `Main` as well. + +[!code-csharp[csProgGuideParameters#9](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#9)] + +In this example, the parameters need to be passed by reference to affect the variables in the calling program. If you remove the `ref` keyword from both the method header and the method call, no changes will take place in the calling program. + +## How to know the difference between passing a struct and passing a class reference to a method + +The following example demonstrates how passing a [struct](../builtin-types/struct.md) to a method differs from passing a [class](class.md) instance to a method. In the example, both of the arguments (struct and class instance) are passed by value, and both methods change the value of one field of the argument. However, the results of the two methods are not the same because what is passed when you pass a struct differs from what is passed when you pass an instance of a class. + +Because a struct is a [value type](../builtin-types/value-types.md), when you [pass a struct by value](#passing-value-type-parameters) to a method, the method receives and operates on a copy of the struct argument. The method has no access to the original struct in the calling method and therefore can't change it in any way. The method can change only the copy. + +A class instance is a [reference type](reference-types.md), not a value type. When [a reference type is passed by value](#passing-reference-type-parameters) to a method, the method receives a copy of the reference to the class instance. That is, the called method receives a copy of the address of the instance, and the calling method retains the original address of the instance. The class instance in the calling method has an address, the parameter in the called method has a copy of the address, and both addresses refer to the same object. Because the parameter contains only a copy of the address, the called method cannot change the address of the class instance in the calling method. However, the called method can use the copy of the address to access the class members that both the original address and the copy of the address reference. If the called method changes a class member, the original class instance in the calling method also changes. + +The output of the following example illustrates the difference. The value of the `willIChange` field of the class instance is changed by the call to method `ClassTaker` because the method uses the address in the parameter to find the specified field of the class instance. The `willIChange` field of the struct in the calling method is not changed by the call to method `StructTaker` because the value of the argument is a copy of the struct itself, not a copy of its address. `StructTaker` changes the copy, and the copy is lost when the call to `StructTaker` is completed. + +[!code-csharp[PassingStructVsClass](snippets/PassParameters.cs#PassByValueOrReference)] + +## Modifiers + +Parameters declared for a method without [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md), are passed to the called method by value. That value can be changed in the method, but the changed value will not be retained when control passes back to the calling procedure. By using a method parameter keyword, you can change this behavior. + +This section describes the keywords you can use when declaring method parameters: + - [params](./params.md) specifies that this parameter may take a variable number of arguments. - - [in](./in-parameter-modifier.md) specifies that this parameter is passed by reference but is only read by the called method. - - [ref](./ref.md) specifies that this parameter is passed by reference and may be read or written by the called method. - - [out](./out-parameter-modifier.md) specifies that this parameter is passed by reference and is written by the called method. - + ## See also - [C# Reference](../index.md) -- [C# Programming Guide](../../programming-guide/index.md) - [C# Keywords](./index.md) +- [Argument lists](~/_csharpstandard/standard/expressions.md#1162-argument-lists) in the [C# Language Specification](~/_csharpstandard/standard/README.md). The language specification is the definitive source for C# syntax and usage. diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index 0ca83ba28c041..644a45111a2ed 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -69,7 +69,7 @@ The previous examples pass value types by reference. You can also use the `ref` [!code-csharp[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#3)] -For more information about how to pass reference types by value and by reference, see [Passing Reference-Type Parameters](../../programming-guide/classes-and-structs/passing-reference-type-parameters.md). +For more information about how to pass reference types by value and by reference, see [Passing Reference-Type Parameters](method-parameters.md#passing-reference-type-parameters). ## Reference return values @@ -149,7 +149,6 @@ When the caller stores the value returned by the `GetBookByTitle` method as a re - [Write safe efficient code](../../write-safe-efficient-code.md) - [Ref returns and ref locals](../../programming-guide/classes-and-structs/ref-returns.md) - [Conditional ref expression](../operators/conditional-operator.md#conditional-ref-expression) -- [Passing Parameters](../../programming-guide/classes-and-structs/passing-parameters.md) - [Method Parameters](method-parameters.md) - [C# Reference](../index.md) - [C# Programming Guide](../../programming-guide/index.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method/Program.cs b/docs/csharp/language-reference/keywords/snippets/PassParameters.cs similarity index 86% rename from docs/csharp/programming-guide/classes-and-structs/snippets/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method/Program.cs rename to docs/csharp/language-reference/keywords/snippets/PassParameters.cs index 581976665f8d9..659043c74476c 100644 --- a/docs/csharp/programming-guide/classes-and-structs/snippets/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method/Program.cs +++ b/docs/csharp/language-reference/keywords/snippets/PassParameters.cs @@ -1,4 +1,9 @@ -class TheClass +using System; + +namespace keywords; + +// +class TheClass { public string? willIChange; } @@ -20,7 +25,7 @@ static void StructTaker(TheStruct s) s.willIChange = "Changed"; } - static void Main() + public static void Main() { TheClass testClass = new TheClass(); TheStruct testStruct = new TheStruct(); @@ -43,3 +48,4 @@ static void Main() Class field = Changed Struct field = Not Changed */ +// diff --git a/docs/csharp/language-reference/keywords/snippets/Program.cs b/docs/csharp/language-reference/keywords/snippets/Program.cs index 5f4e7f6517194..d3bcdd81968fc 100644 --- a/docs/csharp/language-reference/keywords/snippets/Program.cs +++ b/docs/csharp/language-reference/keywords/snippets/Program.cs @@ -15,6 +15,8 @@ static async Task Main(string[] args) UsingStatements.Examples(); Console.WriteLine("================= try-catch Keyword Examples ======================"); await AsyncExceptionExamples.Examples(); + Console.WriteLine("================= pass by value / reference Keyword Examples ======================"); + TestClassAndStruct.Main(); } } diff --git a/docs/csharp/methods.md b/docs/csharp/methods.md index 63c1caedaa5f0..088d71c215c1a 100644 --- a/docs/csharp/methods.md +++ b/docs/csharp/methods.md @@ -291,4 +291,4 @@ For more information, see [Iterators](programming-guide/concepts/iterators.md). - [out](language-reference/keywords/out-parameter-modifier.md) - [ref](language-reference/keywords/ref.md) - [in](language-reference/keywords/in-parameter-modifier.md) -- [Passing Parameters](programming-guide/classes-and-structs/passing-parameters.md) +- [Passing Parameters](language-reference/keywords/method-parameters.md) diff --git a/docs/csharp/misc/cs0177.md b/docs/csharp/misc/cs0177.md index e3038d8b4ef0a..9d7e13e45bddc 100644 --- a/docs/csharp/misc/cs0177.md +++ b/docs/csharp/misc/cs0177.md @@ -12,7 +12,7 @@ ms.assetid: 852a8c2a-2411-4800-af7c-4c572d9900d3 The out parameter 'parameter' must be assigned to before control leaves the current method - A parameter marked with the [out](../language-reference/keywords/out-parameter-modifier.md) keyword was not assigned a value in the method body. For more information, see [Passing Parameters](../programming-guide/classes-and-structs/passing-parameters.md) + A parameter marked with the [out](../language-reference/keywords/out-parameter-modifier.md) keyword was not assigned a value in the method body. For more information, see [Passing Parameters](../language-reference/keywords/method-parameters.md) The following sample generates CS0177: diff --git a/docs/csharp/misc/cs0199.md b/docs/csharp/misc/cs0199.md index ac2dc64d9dbed..1be4518c247f7 100644 --- a/docs/csharp/misc/cs0199.md +++ b/docs/csharp/misc/cs0199.md @@ -12,7 +12,7 @@ ms.assetid: 9eede3f2-b55a-4b85-a05d-6bf177e1c602 Fields of static readonly field 'name' cannot be passed ref or out (except in a static constructor) - A [readonly](../language-reference/keywords/readonly.md) variable must have the same [static](../language-reference/keywords/static.md) usage as the constructor in which you want to pass it as a [ref](../language-reference/keywords/ref.md) or [out](../language-reference/keywords/out-parameter-modifier.md) parameter. For more information, see [Passing Parameters](../programming-guide/classes-and-structs/passing-parameters.md). + A [readonly](../language-reference/keywords/readonly.md) variable must have the same [static](../language-reference/keywords/static.md) usage as the constructor in which you want to pass it as a [ref](../language-reference/keywords/ref.md) or [out](../language-reference/keywords/out-parameter-modifier.md) parameter. For more information, see [Method Parameters](../language-reference/keywords/method-parameters.md). ## Example diff --git a/docs/csharp/misc/cs0206.md b/docs/csharp/misc/cs0206.md index 8e8d7cd732674..09c2f85fc5065 100644 --- a/docs/csharp/misc/cs0206.md +++ b/docs/csharp/misc/cs0206.md @@ -12,7 +12,7 @@ ms.assetid: d2f9838a-d8ae-4342-b8bd-fa5745619a26 A property or indexer may not be passed as an out or ref parameter - A [property](../programming-guide/classes-and-structs/properties.md) is not available to be passed as a [ref](../language-reference/keywords/ref.md) or [out](../language-reference/keywords/out-parameter-modifier.md) parameter. For more information, see [Passing Parameters](../programming-guide/classes-and-structs/passing-parameters.md). + A [property](../programming-guide/classes-and-structs/properties.md) is not available to be passed as a [ref](../language-reference/keywords/ref.md) or [out](../language-reference/keywords/out-parameter-modifier.md) parameter. For more information, see [Method Parameters](../language-reference/keywords/method-parameters.md). ## Example diff --git a/docs/csharp/misc/cs0241.md b/docs/csharp/misc/cs0241.md index 1317e28b40b22..8b208055fffc1 100644 --- a/docs/csharp/misc/cs0241.md +++ b/docs/csharp/misc/cs0241.md @@ -16,7 +16,7 @@ ms.assetid: be31b194-3de5-4aab-b23a-6cf790f940ab Default parameter specifiers are not permitted - [Method parameters](../language-reference/keywords/method-parameters.md) cannot have default values. Use method overloads if you want to achieve the same effect. For more information, see [Passing Parameters](../programming-guide/classes-and-structs/passing-parameters.md). + [Method parameters](../language-reference/keywords/method-parameters.md) cannot have default values. Use method overloads if you want to achieve the same effect. ## Example diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md b/docs/csharp/programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md deleted file mode 100644 index 4e0b3c2e6cc67..0000000000000 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: "How to know the difference between passing a struct and passing a class reference to a method - C# Programming Guide" -description: Passing a struct to a method differs from passing a class instance to a method in C#. This example shows struct and class instance passed by value. -ms.date: 07/20/2015 -helpviewer_keywords: - - "structs [C#], passing as method parameter" - - "passing parameters [C#], structs vs. classes" - - "methods [C#], passing classes vs. structs" -ms.topic: how-to -ms.custom: contperf-fy21q2 -ms.assetid: 9c1313a6-32a8-4ea7-a59f-450f66af628b ---- -# How to know the difference between passing a struct and passing a class reference to a method (C# Programming Guide) - -The following example demonstrates how passing a [struct](../../language-reference/builtin-types/struct.md) to a method differs from passing a [class](../../language-reference/keywords/class.md) instance to a method. In the example, both of the arguments (struct and class instance) are passed by value, and both methods change the value of one field of the argument. However, the results of the two methods are not the same because what is passed when you pass a struct differs from what is passed when you pass an instance of a class. - - Because a struct is a [value type](../../language-reference/builtin-types/value-types.md), when you [pass a struct by value](./passing-value-type-parameters.md) to a method, the method receives and operates on a copy of the struct argument. The method has no access to the original struct in the calling method and therefore can't change it in any way. The method can change only the copy. - - A class instance is a [reference type](../../language-reference/keywords/reference-types.md), not a value type. When [a reference type is passed by value](./passing-reference-type-parameters.md) to a method, the method receives a copy of the reference to the class instance. That is, the called method receives a copy of the address of the instance, and the calling method retains the original address of the instance. The class instance in the calling method has an address, the parameter in the called method has a copy of the address, and both addresses refer to the same object. Because the parameter contains only a copy of the address, the called method cannot change the address of the class instance in the calling method. However, the called method can use the copy of the address to access the class members that both the original address and the copy of the address reference. If the called method changes a class member, the original class instance in the calling method also changes. - - The output of the following example illustrates the difference. The value of the `willIChange` field of the class instance is changed by the call to method `ClassTaker` because the method uses the address in the parameter to find the specified field of the class instance. The `willIChange` field of the struct in the calling method is not changed by the call to method `StructTaker` because the value of the argument is a copy of the struct itself, not a copy of its address. `StructTaker` changes the copy, and the copy is lost when the call to `StructTaker` is completed. - -## Example - - [!code-csharp[PassingStructVsClass](snippets/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method/Program.cs)] - -## See also - -- [C# Programming Guide](../index.md) -- [Classes](../../fundamentals/types/classes.md) -- [Structure types](../../language-reference/builtin-types/struct.md) -- [Passing Parameters](./passing-parameters.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/methods.md b/docs/csharp/programming-guide/classes-and-structs/methods.md index 0142e04c82450..b59cc8713c845 100644 --- a/docs/csharp/programming-guide/classes-and-structs/methods.md +++ b/docs/csharp/programming-guide/classes-and-structs/methods.md @@ -41,7 +41,7 @@ The method definition specifies the names and types of any parameters that are r ## Passing by reference vs. passing by value -By default, when an instance of a [value type](../../language-reference/builtin-types/value-types.md) is passed to a method, its copy is passed instead of the instance itself. Therefore, changes to the argument have no effect on the original instance in the calling method. To pass a value-type instance by reference, use the `ref` keyword. For more information, see [Passing Value-Type Parameters](./passing-value-type-parameters.md). +By default, when an instance of a [value type](../../language-reference/builtin-types/value-types.md) is passed to a method, its copy is passed instead of the instance itself. Therefore, changes to the argument have no effect on the original instance in the calling method. To pass a value-type instance by reference, use the `ref` keyword. For more information, see [Passing Value-Type Parameters](../../language-reference/keywords/method-parameters.md#passing-value-type-parameters). When an object of a reference type is passed to a method, a reference to the object is passed. That is, the method receives not the object itself but an argument that indicates the location of the object. If you change a member of the object by using this reference, the change is reflected in the argument in the calling method, even if you pass the object by value. @@ -55,7 +55,7 @@ Now, if you pass an object that is based on this type to a method, a reference t The example does essentially the same thing as the previous example in that it passes an argument by value to a method. But, because a reference type is used, the result is different. The modification that is made in `ModifyObject` to the `value` field of the parameter, `obj`, also changes the `value` field of the argument, `rt`, in the `TestRefType` method. The `TestRefType` method displays 33 as the output. -For more information about how to pass reference types by reference and by value, see [Passing Reference-Type Parameters](./passing-reference-type-parameters.md) and [Reference Types](../../language-reference/keywords/reference-types.md). +For more information about how to pass reference types by reference and by value, see [Passing Reference-Type Parameters](../../language-reference/keywords/method-parameters.md#passing-reference-type-parameters) and [Reference Types](../../language-reference/keywords/reference-types.md). ## Return values @@ -171,4 +171,4 @@ For more information, see [Iterators](../concepts/iterators.md). - [params](../../language-reference/keywords/params.md) - [out](../../language-reference/keywords/out.md) - [ref](../../language-reference/keywords/ref.md) -- [Passing Parameters](passing-parameters.md) +- [Method Parameters](../../language-reference/keywords/method-parameters.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/passing-parameters.md b/docs/csharp/programming-guide/classes-and-structs/passing-parameters.md deleted file mode 100644 index ef0d0fb3a2ef6..0000000000000 --- a/docs/csharp/programming-guide/classes-and-structs/passing-parameters.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: "Passing Parameters - C# Programming Guide" -description: You can pass an argument to a parameter in C# by value or reference. Changes to an argument passed by reference persist. Use ref or out to pass by reference. -ms.date: 07/20/2015 -helpviewer_keywords: - - "parameters [C#], passing" - - "passing parameters [C#]" - - "arguments [C#]" - - "methods [C#], passing parameters" - - "C# language, method parameters" -ms.assetid: a5c3003f-7441-4710-b8b1-c79de77e0b77 ---- -# Passing Parameters (C# Programming Guide) - -In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment. To pass a parameter by reference with the intent of changing the value, use the `ref`, or `out` keyword. To pass by reference with the intent of avoiding copying but not changing the value, use the `in` modifier. For simplicity, only the `ref` keyword is used in the examples in this topic. For more information about the difference between `in`, `ref`, and `out`, see [in](../../language-reference/keywords/in-parameter-modifier.md), [ref](../../language-reference/keywords/ref.md), and [out](../../language-reference/keywords/out-parameter-modifier.md). - - The following example illustrates the difference between value and reference parameters. - - [!code-csharp[csProgGuideParameters#10](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#10)] - - For more information, see the following topics: - -- [Passing Value-Type Parameters](./passing-value-type-parameters.md) - -- [Passing Reference-Type Parameters](./passing-reference-type-parameters.md) - -## C# Language Specification - -For more information, see [Argument lists](~/_csharpstandard/standard/expressions.md#1162-argument-lists) in the [C# Language Specification](~/_csharpstandard/standard/README.md). The language specification is the definitive source for C# syntax and usage. - -## See also - -- [C# Programming Guide](../index.md) -- [Methods](./methods.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters.md b/docs/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters.md deleted file mode 100644 index 3c8ea8326e422..0000000000000 --- a/docs/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: "Passing Reference-Type Parameters - C# Programming Guide" -description: When you pass a reference-type parameter by value in C#, the data in the referenced object can change, but not the value of the reference itself. -ms.date: 07/20/2015 -helpviewer_keywords: - - "method parameters [C#], reference types" - - "parameters [C#], reference" -ms.assetid: 9e6eb65c-942e-48ab-920a-b7ba9df4ea20 ---- -# Passing Reference-Type Parameters (C# Programming Guide) - -A variable of a [reference type](../../language-reference/keywords/reference-types.md) does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data belonging to the referenced object, such as the value of a class member. However, you cannot change the value of the reference itself; for example, you cannot use the same reference to allocate memory for a new object and have it persist outside the method. To do that, pass the parameter using the [ref](../../language-reference/keywords/ref.md) or [out](../../language-reference/keywords/out-parameter-modifier.md) keyword. For simplicity, the following examples use `ref`. - -## Passing Reference Types by Value - - The following example demonstrates passing a reference-type parameter, `arr`, by value, to a method, `Change`. Because the parameter is a reference to `arr`, it is possible to change the values of the array elements. However, the attempt to reassign the parameter to a different memory location only works inside the method and does not affect the original variable, `arr`. - - [!code-csharp[csProgGuideParameters#7](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#7)] - - In the preceding example, the array, `arr`, which is a reference type, is passed to the method without the `ref` parameter. In such a case, a copy of the reference, which points to `arr`, is passed to the method. The output shows that it is possible for the method to change the contents of an array element, in this case from `1` to `888`. However, allocating a new portion of memory by using the [new](../../language-reference/operators/new-operator.md) operator inside the `Change` method makes the variable `pArray` reference a new array. Thus, any changes after that will not affect the original array, `arr`, which is created inside `Main`. In fact, two arrays are created in this example, one inside `Main` and one inside the `Change` method. - -## Passing Reference Types by Reference - - The following example is the same as the previous example, except that the `ref` keyword is added to the method header and call. Any changes that take place in the method affect the original variable in the calling program. - - [!code-csharp[csProgGuideParameters#8](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#8)] - - All of the changes that take place inside the method affect the original array in `Main`. In fact, the original array is reallocated using the `new` operator. Thus, after calling the `Change` method, any reference to `arr` points to the five-element array, which is created in the `Change` method. - -## Swapping Two Strings - - Swapping strings is a good example of passing reference-type parameters by reference. In the example, two strings, `str1` and `str2`, are initialized in `Main` and passed to the `SwapStrings` method as parameters modified by the `ref` keyword. The two strings are swapped inside the method and inside `Main` as well. - - [!code-csharp[csProgGuideParameters#9](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#9)] - - In this example, the parameters need to be passed by reference to affect the variables in the calling program. If you remove the `ref` keyword from both the method header and the method call, no changes will take place in the calling program. - - For more information about strings, see [string](../../language-reference/builtin-types/reference-types.md). - -## See also - -- [C# Programming Guide](../index.md) -- [Passing Parameters](./passing-parameters.md) -- [ref](../../language-reference/keywords/ref.md) -- [in](../../language-reference/keywords/in-parameter-modifier.md) -- [out](../../language-reference/keywords/out.md) -- [Reference Types](../../language-reference/keywords/reference-types.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/passing-value-type-parameters.md b/docs/csharp/programming-guide/classes-and-structs/passing-value-type-parameters.md deleted file mode 100644 index 7074520d8c4b6..0000000000000 --- a/docs/csharp/programming-guide/classes-and-structs/passing-value-type-parameters.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "Passing Value-Type Parameters - C# Programming Guide" -description: When you pass a value-type variable to a method by value in C#, any changes have no effect on the original data. To change the value, pass by reference. -ms.date: 07/20/2015 -helpviewer_keywords: - - "method parameters [C#], value types" - - "parameters [C#], value" -ms.assetid: 193ab86f-5f9b-4359-ac29-7cdf8afad3a6 ---- -# Passing Value-Type Parameters (C# Programming Guide) - -A [value-type](../../language-reference/builtin-types/value-types.md) variable contains its data directly as opposed to a [reference-type](../../language-reference/keywords/reference-types.md) variable, which contains a reference to its data. Passing a value-type variable to a method by value means passing a copy of the variable to the method. Any changes to the parameter that take place inside the method have no effect on the original data stored in the argument variable. If you want the called method to change the value of the argument, you must pass it by reference, using the [ref](../../language-reference/keywords/ref.md) or [out](../../language-reference/keywords/out-parameter-modifier.md) keyword. You may also use the [in](../../language-reference/keywords/in-parameter-modifier.md) keyword to pass a value parameter by reference to avoid the copy while guaranteeing that the value will not be changed. For simplicity, the following examples use `ref`. - -## Passing Value Types by Value - - The following example demonstrates passing value-type parameters by value. The variable `n` is passed by value to the method `SquareIt`. Any changes that take place inside the method have no effect on the original value of the variable. - - [!code-csharp[csProgGuideParameters#3](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#3)] - - The variable `n` is a value type. It contains its data, the value `5`. When `SquareIt` is invoked, the contents of `n` are copied into the parameter `x`, which is squared inside the method. In `Main`, however, the value of `n` is the same after calling the `SquareIt` method as it was before. The change that takes place inside the method only affects the local variable `x`. - -## Passing Value Types by Reference - - The following example is the same as the previous example, except that the argument is passed as a `ref` parameter. The value of the underlying argument, `n`, is changed when `x` is changed in the method. - - [!code-csharp[csProgGuideParameters#4](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#4)] - - In this example, it is not the value of `n` that is passed; rather, a reference to `n` is passed. The parameter `x` is not an [int](../../language-reference/builtin-types/integral-numeric-types.md); it is a reference to an `int`, in this case, a reference to `n`. Therefore, when `x` is squared inside the method, what actually is squared is what `x` refers to, `n`. - -## Swapping Value Types - - A common example of changing the values of arguments is a swap method, where you pass two variables to the method, and the method swaps their contents. You must pass the arguments to the swap method by reference. Otherwise, you swap local copies of the parameters inside the method, and no change occurs in the calling method. The following example swaps integer values. - - [!code-csharp[csProgGuideParameters#5](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#5)] - - When you call the `SwapByRef` method, use the `ref` keyword in the call, as shown in the following example. - - [!code-csharp[csProgGuideParameters#6](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#6)] - -## See also - -- [C# Programming Guide](../index.md) -- [Passing Parameters](./passing-parameters.md) -- [Passing Reference-Type Parameters](./passing-reference-type-parameters.md) diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 319334d201500..67feb28d3c15a 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -666,16 +666,6 @@ items: href: programming-guide/classes-and-structs/local-functions.md - name: Ref returns and ref locals href: programming-guide/classes-and-structs/ref-returns.md - - name: Parameters - items: - - name: Passing parameters - href: programming-guide/classes-and-structs/passing-parameters.md - - name: Passing Value-Type Parameters - href: programming-guide/classes-and-structs/passing-value-type-parameters.md - - name: Passing Reference-Type Parameters - href: programming-guide/classes-and-structs/passing-reference-type-parameters.md - - name: "How to know the difference between passing a struct and passing a class reference to a method" - href: programming-guide/classes-and-structs/how-to-know-the-difference-passing-a-struct-and-passing-a-class-to-a-method.md - name: Implicitly Typed Local Variables href: programming-guide/classes-and-structs/implicitly-typed-local-variables.md - name: "How to use implicitly typed local variables and arrays in a query expression" From 2e844283f66b380501b892bc4ebb76c8261a29f2 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 2 Sep 2022 10:59:18 -0400 Subject: [PATCH 03/16] Edit method parameters combined article. Update samples, provide better definition for passing reference parameters and value parameters by reference or by value. --- .../keywords/method-parameters.md | 89 +++---- .../csharp/language-reference/keywords/ref.md | 2 +- .../keywords/snippets/ParameterModifiers.cs | 112 ++++++++ .../keywords/snippets/Program.cs | 5 + .../classes-and-structs/methods.md | 4 +- .../csProgGuideParameters/CS/Parameters.cs | 245 ------------------ .../csProgGuideParameters/CS/Project.csproj | 7 - 7 files changed, 163 insertions(+), 301 deletions(-) create mode 100644 docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs delete mode 100644 samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs delete mode 100644 samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Project.csproj diff --git a/docs/csharp/language-reference/keywords/method-parameters.md b/docs/csharp/language-reference/keywords/method-parameters.md index 10dc21742d414..6eb10da01b2e3 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -1,7 +1,7 @@ --- description: "Method Parameters - C# Reference" title: "Method Parameters - C# Reference" -ms.date: 08/30/2022 +ms.date: 09/01/2022 helpviewer_keywords: - "methods [C#], parameters" - "method parameters [C#]" @@ -10,85 +10,82 @@ ms.assetid: 680e39ff-775b-48b0-9f47-4186a5bfc4a1 --- # Method Parameters (C# Reference) -In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment. To pass a parameter by reference with the intent of changing the value, use the `ref`, or `out` keyword. To pass by reference with the intent of avoiding copying but not changing the value, use the `in` modifier. For simplicity, only the `ref` keyword is used in the examples in this topic. For more information about the difference between `in`, `ref`, and `out`, see [in](in-parameter-modifier.md), [ref](ref.md), and [out](out-parameter-modifier.md). +In C#, arguments can be passed to parameters either by value or by reference. Remember that C# types can be either reference types (`class`) or value types (`struct`): -The following example illustrates the difference between value and reference parameters. +- *Pass by value* means **passing a copy of the variable** to the method. +- *Pass by reference* means **passing access to the variable** to the method. +- A variable of a *reference type* contains a reference to its data. +- A variable of a *structure type* contains its data directly. -[!code-csharp[csProgGuideParameters#10](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#10)] +Because a struct is a [value type](../builtin-types/value-types.md), when you [pass a struct by value](#pass-a-value-type-by-value) to a method, the method receives and operates on a copy of the struct argument. The method has no access to the original struct in the calling method and therefore can't change it in any way. The method can change only the copy. -## Passing Value-Type Parameters +A class instance is a [reference type](reference-types.md), not a value type. When [a reference type is passed by value](#pass-a-reference-type-by-value) to a method, the method receives a copy of the reference to the class instance. That is, the called method receives a copy of the address of the instance, and the calling method retains the original address of the instance. The class instance in the calling method has an address, the parameter in the called method has a copy of the address, and both addresses refer to the same object. Because the parameter contains only a copy of the address, the called method cannot change the address of the class instance in the calling method. However, the called method can use the copy of the address to access the class members that both the original address and the copy of the address reference. If the called method changes a class member, the original class instance in the calling method also changes. -A [value-type](../builtin-types/value-types.md) variable contains its data directly as opposed to a [reference-type](reference-types.md) variable, which contains a reference to its data. Passing a value-type variable to a method by value means passing a copy of the variable to the method. Any changes to the parameter that take place inside the method have no effect on the original data stored in the argument variable. If you want the called method to change the value of the argument, you must pass it by reference, using the [ref](ref.md) or [out](out-parameter-modifier.md) keyword. You may also use the [in](in-parameter-modifier.md) keyword to pass a value parameter by reference to avoid the copy while guaranteeing that the value will not be changed. For simplicity, the following examples use `ref`. +The output of the following example illustrates the difference. The value of the `willIChange` field of the class instance is changed by the call to method `ClassTaker` because the method uses the address in the parameter to find the specified field of the class instance. The `willIChange` field of the struct in the calling method is not changed by the call to method `StructTaker` because the value of the argument is a copy of the struct itself, not a copy of its address. `StructTaker` changes the copy, and the copy is lost when the call to `StructTaker` is completed. -### Passing Value Types by Value +:::code language="csharp" source="./snippets/PassParameters.cs" id="PassByValueOrReference"::: -The following example demonstrates passing value-type parameters by value. The variable `n` is passed by value to the method `SquareIt`. Any changes that take place inside the method have no effect on the original value of the variable. +How an argument is passed, and whether it's a reference type or value type controls what modifications made to the argument are visible from the caller. -[!code-csharp[csProgGuideParameters#3](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#3)] +## Pass a value type by value -The variable `n` is a value type. It contains its data, the value `5`. When `SquareIt` is invoked, the contents of `n` are copied into the parameter `x`, which is squared inside the method. In `Main`, however, the value of `n` is the same after calling the `SquareIt` method as it was before. The change that takes place inside the method only affects the local variable `x`. +When you pass a *value* type *by value*: -### Passing Value Types by Reference +- If the method assigns the parameter to refer to a different object, those changes **aren't** visible from the caller. +- If the method modifies the state of the object referred to by the parameter, those changes **aren't** visible from the caller. -The following example is the same as the previous example, except that the argument is passed as a `ref` parameter. The value of the underlying argument, `n`, is changed when `x` is changed in the method. +The following example demonstrates passing value-type parameters by value. The variable `n` is passed by value to the method `SquareIt`. Any changes that take place inside the method have no effect on the original value of the variable. -[!code-csharp[csProgGuideParameters#4](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#4)] +:::code language="csharp" source="./snippets/ParameterModifiers.cs" id="SnippetPassValueByValue"::: -In this example, it is not the value of `n` that is passed; rather, a reference to `n` is passed. The parameter `x` is not an [int](../builtin-types/integral-numeric-types.md); it is a reference to an `int`, in this case, a reference to `n`. Therefore, when `x` is squared inside the method, what actually is squared is what `x` refers to, `n`. +The variable `n` is a value type. It contains its data, the value `5`. When `SquareIt` is invoked, the contents of `n` are copied into the parameter `x`, which is squared inside the method. In `Main`, however, the value of `n` is the same after calling the `SquareIt` method as it was before. The change that takes place inside the method only affects the local variable `x`. + +## Pass a value type by reference -### Swapping Value Types +When you pass a *value* type *by by reference*: -A common example of changing the values of arguments is a swap method, where you pass two variables to the method, and the method swaps their contents. You must pass the arguments to the swap method by reference. Otherwise, you swap local copies of the parameters inside the method, and no change occurs in the calling method. The following example swaps integer values. +- If the method assigns the parameter to refer to a different object, those changes **aren't** visible from the caller. +- If the method modifies the state of the object referred to by the parameter, those changes **aren't** visible from the caller. -[!code-csharp[csProgGuideParameters#5](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#5)] +The following example is the same as the previous example, except that the argument is passed as a `ref` parameter. The value of the underlying argument, `n`, is changed when `x` is changed in the method. -When you call the `SwapByRef` method, use the `ref` keyword in the call, as shown in the following example. +:::code language="csharp" source="./snippets/ParameterModifiers.cs" id="SnippetPassValueByReference"::: -[!code-csharp[csProgGuideParameters#6](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#6)] +In this example, it is not the value of `n` that is passed; rather, a reference to `n` is passed. The parameter `x` is not an [int](../builtin-types/integral-numeric-types.md); it is a reference to an `int`, in this case, a reference to `n`. Therefore, when `x` is squared inside the method, what actually is squared is what `x` refers to, `n`. -## Passing Reference-Type Parameters +## Pass a reference type by value -A variable of a [reference type](reference-types.md) does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data belonging to the referenced object, such as the value of a class member. However, you cannot change the value of the reference itself; for example, you cannot use the same reference to allocate memory for a new object and have it persist outside the method. To do that, pass the parameter using the [ref](ref.md) or [out](out-parameter-modifier.md) keyword. For simplicity, the following examples use `ref`. +When you pass a *reference* type *by value*: -### Passing Reference Types by Value +- If the method assigns the parameter to refer to a different object, those changes **aren't** visible from the caller. +- If the method modifies the state of the object referred to by the parameter, those changes **are** visible from the caller. The following example demonstrates passing a reference-type parameter, `arr`, by value, to a method, `Change`. Because the parameter is a reference to `arr`, it is possible to change the values of the array elements. However, the attempt to reassign the parameter to a different memory location only works inside the method and does not affect the original variable, `arr`. -[!code-csharp[csProgGuideParameters#7](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#7)] +:::code language="csharp" source="./snippets/ParameterModifiers.cs" id="SnippetPassReferenceByValue"::: In the preceding example, the array, `arr`, which is a reference type, is passed to the method without the `ref` parameter. In such a case, a copy of the reference, which points to `arr`, is passed to the method. The output shows that it is possible for the method to change the contents of an array element, in this case from `1` to `888`. However, allocating a new portion of memory by using the [new](../operators/new-operator.md) operator inside the `Change` method makes the variable `pArray` reference a new array. Thus, any changes after that will not affect the original array, `arr`, which is created inside `Main`. In fact, two arrays are created in this example, one inside `Main` and one inside the `Change` method. -### Passing Reference Types by Reference - -The following example is the same as the previous example, except that the `ref` keyword is added to the method header and call. Any changes that take place in the method affect the original variable in the calling program. - -[!code-csharp[csProgGuideParameters#8](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#8)] - -All of the changes that take place inside the method affect the original array in `Main`. In fact, the original array is reallocated using the `new` operator. Thus, after calling the `Change` method, any reference to `arr` points to the five-element array, which is created in the `Change` method. - -### Swapping Two Strings - -Swapping strings is a good example of passing reference-type parameters by reference. In the example, two strings, `str1` and `str2`, are initialized in `Main` and passed to the `SwapStrings` method as parameters modified by the `ref` keyword. The two strings are swapped inside the method and inside `Main` as well. - -[!code-csharp[csProgGuideParameters#9](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs#9)] +## Pass a reference type by reference -In this example, the parameters need to be passed by reference to affect the variables in the calling program. If you remove the `ref` keyword from both the method header and the method call, no changes will take place in the calling program. +When you pass a *reference* type *by reference*: -## How to know the difference between passing a struct and passing a class reference to a method +- If the method assigns the parameter to refer to a different object, those changes **are** visible from the caller. +- If the method modifies the state of the object referred to by the parameter, those changes **are** visible from the caller. -The following example demonstrates how passing a [struct](../builtin-types/struct.md) to a method differs from passing a [class](class.md) instance to a method. In the example, both of the arguments (struct and class instance) are passed by value, and both methods change the value of one field of the argument. However, the results of the two methods are not the same because what is passed when you pass a struct differs from what is passed when you pass an instance of a class. - -Because a struct is a [value type](../builtin-types/value-types.md), when you [pass a struct by value](#passing-value-type-parameters) to a method, the method receives and operates on a copy of the struct argument. The method has no access to the original struct in the calling method and therefore can't change it in any way. The method can change only the copy. - -A class instance is a [reference type](reference-types.md), not a value type. When [a reference type is passed by value](#passing-reference-type-parameters) to a method, the method receives a copy of the reference to the class instance. That is, the called method receives a copy of the address of the instance, and the calling method retains the original address of the instance. The class instance in the calling method has an address, the parameter in the called method has a copy of the address, and both addresses refer to the same object. Because the parameter contains only a copy of the address, the called method cannot change the address of the class instance in the calling method. However, the called method can use the copy of the address to access the class members that both the original address and the copy of the address reference. If the called method changes a class member, the original class instance in the calling method also changes. +The following example is the same as the previous example, except that the `ref` keyword is added to the method header and call. Any changes that take place in the method affect the original variable in the calling program. -The output of the following example illustrates the difference. The value of the `willIChange` field of the class instance is changed by the call to method `ClassTaker` because the method uses the address in the parameter to find the specified field of the class instance. The `willIChange` field of the struct in the calling method is not changed by the call to method `StructTaker` because the value of the argument is a copy of the struct itself, not a copy of its address. `StructTaker` changes the copy, and the copy is lost when the call to `StructTaker` is completed. +:::code language="csharp" source="./snippets/ParameterModifiers.cs" id="SnippetPassReferenceByReference"::: -[!code-csharp[PassingStructVsClass](snippets/PassParameters.cs#PassByValueOrReference)] +All of the changes that take place inside the method affect the original array in `Main`. In fact, the original array is reallocated using the `new` operator. Thus, after calling the `Change` method, any reference to `arr` points to the five-element array, which is created in the `Change` method. ## Modifiers -Parameters declared for a method without [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md), are passed to the called method by value. That value can be changed in the method, but the changed value will not be retained when control passes back to the calling procedure. By using a method parameter keyword, you can change this behavior. +Parameters declared for a method without [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md), are passed to the called method by value. The `ref`, `in`, and `out` modifiers differ in assignment rules: + +- The argument for a `ref` parameter must be definitely assigned. The called method may reassign that parameter. +- The argument for an `in` parameter must be definitely assigned. The called method can't reassign that parameter. +- The argument for an `out` parameter needn't be definitely assigned. The called method must assign the parameter. This section describes the keywords you can use when declaring method parameters: diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index 644a45111a2ed..ee4ad8954dcbe 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -69,7 +69,7 @@ The previous examples pass value types by reference. You can also use the `ref` [!code-csharp[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#3)] -For more information about how to pass reference types by value and by reference, see [Passing Reference-Type Parameters](method-parameters.md#passing-reference-type-parameters). +For more information about how to pass reference types by value and by reference, see [Passing Reference-Type Parameters](method-parameters.md). ## Reference return values diff --git a/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs b/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs new file mode 100644 index 0000000000000..1499fa42d2287 --- /dev/null +++ b/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace keywords; +internal class ParameterModifiers +{ + internal static void PassValueByValue() + { + // + int n = 5; + System.Console.WriteLine("The value before calling the method: {0}", n); + + SquareIt(n); // Passing the variable by value. + System.Console.WriteLine("The value after calling the method: {0}", n); + + // Keep the console window open in debug mode. + System.Console.WriteLine("Press any key to exit."); + System.Console.ReadKey(); + + static void SquareIt(int x) + // The parameter x is passed by value. + // Changes to x will not affect the original value of x. + { + x *= x; + System.Console.WriteLine("The value inside the method: {0}", x); + } + /* Output: + The value before calling the method: 5 + The value inside the method: 25 + The value after calling the method: 5 + */ + // + } + + internal static void PassingValueByReferemce() + { + // + int n = 5; + System.Console.WriteLine("The value before calling the method: {0}", n); + + SquareIt(ref n); // Passing the variable by reference. + System.Console.WriteLine("The value after calling the method: {0}", n); + + // Keep the console window open in debug mode. + System.Console.WriteLine("Press any key to exit."); + System.Console.ReadKey(); + + static void SquareIt(ref int x) + // The parameter x is passed by reference. + // Changes to x will affect the original value of x. + { + x *= x; + System.Console.WriteLine("The value inside the method: {0}", x); + } + /* Output: + The value before calling the method: 5 + The value inside the method: 25 + The value after calling the method: 25 + */ + // + } + + internal static void PassingReferenceByValue() + { + // + int[] arr = { 1, 4, 5 }; + System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]); + + Change(arr); + System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]); + + static void Change(int[] pArray) + { + pArray[0] = 888; // This change affects the original element. + pArray = new int[5] { -3, -1, -2, -3, -4 }; // This change is local. + System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]); + } + /* Output: + Inside Main, before calling the method, the first element is: 1 + Inside the method, the first element is: -3 + Inside Main, after calling the method, the first element is: 888 + */ + // + } + + internal static void PassingReferenceByReference() + { + // + int[] arr = { 1, 4, 5 }; + System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]); + + Change(ref arr); + System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]); + + static void Change(ref int[] pArray) + { + // Both of the following changes will affect the original variables: + pArray[0] = 888; + pArray = new int[5] { -3, -1, -2, -3, -4 }; + System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]); + } + /* Output: + Inside Main, before calling the method, the first element is: 1 + Inside the method, the first element is: -3 + Inside Main, after calling the method, the first element is: -3 + */ + // + } +} diff --git a/docs/csharp/language-reference/keywords/snippets/Program.cs b/docs/csharp/language-reference/keywords/snippets/Program.cs index d3bcdd81968fc..a799acf31d569 100644 --- a/docs/csharp/language-reference/keywords/snippets/Program.cs +++ b/docs/csharp/language-reference/keywords/snippets/Program.cs @@ -17,6 +17,11 @@ static async Task Main(string[] args) await AsyncExceptionExamples.Examples(); Console.WriteLine("================= pass by value / reference Keyword Examples ======================"); TestClassAndStruct.Main(); + ParameterModifiers.PassValueByValue(); + ParameterModifiers.PassingValueByReferemce(); + ParameterModifiers.PassingReferenceByValue(); + ParameterModifiers.PassingReferenceByReference(); + } } diff --git a/docs/csharp/programming-guide/classes-and-structs/methods.md b/docs/csharp/programming-guide/classes-and-structs/methods.md index b59cc8713c845..8ca12fdd6d71e 100644 --- a/docs/csharp/programming-guide/classes-and-structs/methods.md +++ b/docs/csharp/programming-guide/classes-and-structs/methods.md @@ -41,7 +41,7 @@ The method definition specifies the names and types of any parameters that are r ## Passing by reference vs. passing by value -By default, when an instance of a [value type](../../language-reference/builtin-types/value-types.md) is passed to a method, its copy is passed instead of the instance itself. Therefore, changes to the argument have no effect on the original instance in the calling method. To pass a value-type instance by reference, use the `ref` keyword. For more information, see [Passing Value-Type Parameters](../../language-reference/keywords/method-parameters.md#passing-value-type-parameters). +By default, when an instance of a [value type](../../language-reference/builtin-types/value-types.md) is passed to a method, its copy is passed instead of the instance itself. Therefore, changes to the argument have no effect on the original instance in the calling method. To pass a value-type instance by reference, use the `ref` keyword. For more information, see [Passing Value-Type Parameters](../../language-reference/keywords/method-parameters.md). When an object of a reference type is passed to a method, a reference to the object is passed. That is, the method receives not the object itself but an argument that indicates the location of the object. If you change a member of the object by using this reference, the change is reflected in the argument in the calling method, even if you pass the object by value. @@ -55,7 +55,7 @@ Now, if you pass an object that is based on this type to a method, a reference t The example does essentially the same thing as the previous example in that it passes an argument by value to a method. But, because a reference type is used, the result is different. The modification that is made in `ModifyObject` to the `value` field of the parameter, `obj`, also changes the `value` field of the argument, `rt`, in the `TestRefType` method. The `TestRefType` method displays 33 as the output. -For more information about how to pass reference types by reference and by value, see [Passing Reference-Type Parameters](../../language-reference/keywords/method-parameters.md#passing-reference-type-parameters) and [Reference Types](../../language-reference/keywords/reference-types.md). +For more information about how to pass reference types by reference and by value, see [Passing Reference-Type Parameters](../../language-reference/keywords/method-parameters.md) and [Reference Types](../../language-reference/keywords/reference-types.md). ## Return values diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs deleted file mode 100644 index 1b2d533013f7f..0000000000000 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Parameters.cs +++ /dev/null @@ -1,245 +0,0 @@ -using System; - -namespace CsCsrefProgrammingParameters -{ - //------------------------------------------------------------------------- - class WrapParameters - { - // - // Passing by value - static void Square(int x) - { - // code... - } - // - - // - // Passing by reference - static void Square(ref int x) - { - // code... - } - // - } - - //------------------------------------------------------------------------- - namespace WrapPassingVals - { - // - class PassingValByVal - { - static void SquareIt(int x) - // The parameter x is passed by value. - // Changes to x will not affect the original value of x. - { - x *= x; - System.Console.WriteLine("The value inside the method: {0}", x); - } - static void Main() - { - int n = 5; - System.Console.WriteLine("The value before calling the method: {0}", n); - - SquareIt(n); // Passing the variable by value. - System.Console.WriteLine("The value after calling the method: {0}", n); - - // Keep the console window open in debug mode. - System.Console.WriteLine("Press any key to exit."); - System.Console.ReadKey(); - } - } - /* Output: - The value before calling the method: 5 - The value inside the method: 25 - The value after calling the method: 5 - */ - // - - // - class PassingValByRef - { - static void SquareIt(ref int x) - // The parameter x is passed by reference. - // Changes to x will affect the original value of x. - { - x *= x; - System.Console.WriteLine("The value inside the method: {0}", x); - } - static void Main() - { - int n = 5; - System.Console.WriteLine("The value before calling the method: {0}", n); - - SquareIt(ref n); // Passing the variable by reference. - System.Console.WriteLine("The value after calling the method: {0}", n); - - // Keep the console window open in debug mode. - System.Console.WriteLine("Press any key to exit."); - System.Console.ReadKey(); - } - } - /* Output: - The value before calling the method: 5 - The value inside the method: 25 - The value after calling the method: 25 - */ - // - - class SwappingValTypes - { - // - static void SwapByRef(ref int x, ref int y) - { - int temp = x; - x = y; - y = temp; - } - // - - // - static void Main() - { - int i = 2, j = 3; - System.Console.WriteLine("i = {0} j = {1}" , i, j); - - SwapByRef (ref i, ref j); - - System.Console.WriteLine("i = {0} j = {1}" , i, j); - - // Keep the console window open in debug mode. - System.Console.WriteLine("Press any key to exit."); - System.Console.ReadKey(); - } - /* Output: - i = 2 j = 3 - i = 3 j = 2 - */ - // - } - } - - //------------------------------------------------------------------------- - namespace WrapPassingRefs - { - // - class PassingRefByVal - { - static void Change(int[] pArray) - { - pArray[0] = 888; // This change affects the original element. - pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local. - System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]); - } - - static void Main() - { - int[] arr = {1, 4, 5}; - System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]); - - Change(arr); - System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]); - } - } - /* Output: - Inside Main, before calling the method, the first element is: 1 - Inside the method, the first element is: -3 - Inside Main, after calling the method, the first element is: 888 - */ - // - - // - class PassingRefByRef - { - static void Change(ref int[] pArray) - { - // Both of the following changes will affect the original variables: - pArray[0] = 888; - pArray = new int[5] {-3, -1, -2, -3, -4}; - System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]); - } - - static void Main() - { - int[] arr = {1, 4, 5}; - System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]); - - Change(ref arr); - System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]); - } - } - /* Output: - Inside Main, before calling the method, the first element is: 1 - Inside the method, the first element is: -3 - Inside Main, after calling the method, the first element is: -3 - */ - // - - // - class SwappingStrings - { - static void SwapStrings(ref string s1, ref string s2) - // The string parameter is passed by reference. - // Any changes on parameters will affect the original variables. - { - string temp = s1; - s1 = s2; - s2 = temp; - System.Console.WriteLine("Inside the method: {0} {1}", s1, s2); - } - - static void Main() - { - string str1 = "John"; - string str2 = "Smith"; - System.Console.WriteLine("Inside Main, before swapping: {0} {1}", str1, str2); - - SwapStrings(ref str1, ref str2); // Passing strings by reference - System.Console.WriteLine("Inside Main, after swapping: {0} {1}", str1, str2); - } - } - /* Output: - Inside Main, before swapping: John Smith - Inside the method: Smith John - Inside Main, after swapping: Smith John - */ - // - } - - namespace PassByValueAndRef - { - // - class Program - { - static void Main(string[] args) - { - int arg; - - // Passing by value. - // The value of arg in Main is not changed. - arg = 4; - squareVal(arg); - Console.WriteLine(arg); - // Output: 4 - - // Passing by reference. - // The value of arg in Main is changed. - arg = 4; - squareRef(ref arg); - Console.WriteLine(arg); - // Output: 16 - } - - static void squareVal(int valParameter) - { - valParameter *= valParameter; - } - - // Passing by reference - static void squareRef(ref int refParameter) - { - refParameter *= refParameter; - } - } - // - } -} diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Project.csproj b/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Project.csproj deleted file mode 100644 index b83f0211b39c5..0000000000000 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideParameters/CS/Project.csproj +++ /dev/null @@ -1,7 +0,0 @@ - - - - Library - net6.0 - - From 70624eafc982749a194d01ffc042f70e6ecc6e58 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 6 Sep 2022 17:02:25 -0400 Subject: [PATCH 04/16] add first draft for *safe_to_escape* and *ref_safe_to_escape* Not happy with them yet, but there's it's a start. --- .../language-reference/keywords/method-parameters.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/csharp/language-reference/keywords/method-parameters.md b/docs/csharp/language-reference/keywords/method-parameters.md index 6eb10da01b2e3..6455a780f4dcc 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -79,6 +79,15 @@ The following example is the same as the previous example, except that the `ref` All of the changes that take place inside the method affect the original array in `Main`. In fact, the original array is reallocated using the `new` operator. Thus, after calling the `Change` method, any reference to `arr` points to the five-element array, which is created in the `Change` method. +## Scope of references and values + +Methods can store the values of parameters in fields. When parameters are passed by value, that's always safe. Values are copied, and reference types are reachable when stored in a field. Passing parameters by reference safely requires the compiler to define when its safe to assign a reference to a new variable. For every expression, the compiler defines a *scope* that bounds access to an expression or variable. The compiler uses to scopes: *safe_to_escape* and *ref_safe_to_escape*. + +- The *safe_to_escape* scope defines the scope where any expression can be safely accessed. +- The *ref_safe_to_escape* scope defines the scope where a *reference* to any expressions can be safely accessed or modified + +Informally, you can think of these scopes as the mechanism to ensure your code never accesses or modifies a reference that's no longer valid. A reference is valid as long as it refers to a valid object or struct. The *safe_to_escape* scope defines when a variable can be assigned or reassigned. The *ref_safe_to_escape* scope defines when a variable can *ref* assigned or *ref* reassigned. Assignment assigns a variable to a new value. *ref assignment* assigns the variable to *refer to* a different storage location. + ## Modifiers Parameters declared for a method without [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md), are passed to the called method by value. The `ref`, `in`, and `out` modifiers differ in assignment rules: From 8d5a6fc805908a068501c75ce8ba6b1100ca0c91 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 7 Sep 2022 15:38:56 -0400 Subject: [PATCH 05/16] Move information on ref returns and ref locals - Move `var` article to form the core of the new "Declaration statements" article. - Add content from Programming guide article on "ref returns and ref locals" to new declaration article. - Add content from Prog Guide article on "ref returns" (same article) to the section on `return` in the Jump statements article. --- .openpublishing.redirection.csharp.json | 8 ++ .../7.0/reflection-invoke-exceptions.md | 2 +- .../coding-style/coding-conventions.md | 2 +- .../fundamentals/object-oriented/index.md | 2 +- .../fundamentals/types/anonymous-types.md | 2 +- docs/csharp/fundamentals/types/index.md | 4 +- .../builtin-types/struct.md | 2 +- .../compiler-messages/cs1942.md | 2 +- .../language-reference/keywords/async.md | 2 +- .../keywords/from-clause.md | 2 +- .../language-reference/keywords/index.md | 2 +- .../csharp/language-reference/keywords/ref.md | 2 +- .../csharp/language-reference/keywords/var.md | 49 ----------- .../operators/conditional-operator.md | 2 +- .../operators/new-operator.md | 2 +- .../statements/declarations.md} | 83 +++++++++++-------- .../statements/iteration-statements.md | 2 +- .../statements/jump-statements.md | 45 ++++++++-- docs/csharp/linq/query-expression-basics.md | 2 +- docs/csharp/linq/write-linq-queries.md | 2 +- docs/csharp/misc/cs1949.md | 2 +- .../arrays/implicitly-typed-arrays.md | 2 +- ...iables-and-arrays-in-a-query-expression.md | 3 +- .../implicitly-typed-local-variables.md | 2 +- .../classes-and-structs/methods.md | 4 +- .../linq/features-that-support-linq.md | 2 +- .../concepts/linq/linq-and-generic-types.md | 2 +- ...-relationships-in-linq-query-operations.md | 4 +- .../linq/walkthrough-writing-queries-linq.md | 4 +- docs/csharp/toc.yml | 7 +- docs/csharp/tutorials/console-teleprompter.md | 2 +- .../whats-new/csharp-version-history.md | 5 +- docs/csharp/write-safe-efficient-code.md | 3 +- docs/framework/whats-new/index.md | 2 +- .../style-rules/ide0007-ide0008.md | 4 +- 35 files changed, 137 insertions(+), 130 deletions(-) delete mode 100644 docs/csharp/language-reference/keywords/var.md rename docs/csharp/{programming-guide/classes-and-structs/ref-returns.md => language-reference/statements/declarations.md} (68%) diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index b008e5da2599a..1f764e0114a7b 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -735,6 +735,10 @@ "source_path_from_root": "/docs/csharp/language-reference/keywords/value-types.md", "redirect_url": "/dotnet/csharp/language-reference/builtin-types/value-types" }, + { + "source_path_from_root": "/docs/csharp/language-reference/keywords/var.md", + "redirect_url": "/dotnet/csharp/language-reference/statements/declarations#var" + }, { "source_path_from_root": "/docs/csharp/language-reference/keywords/void.md", "redirect_url": "/dotnet/csharp/language-reference/builtin-types/void" @@ -1092,6 +1096,10 @@ "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/records.md", "redirect_url": "/dotnet/csharp/fundamentals/types/records" }, + { + "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/ref-returns.md", + "redirect_url": "/dotnet/csharp/language-reference/statements/declarations" + }, { "source_path_from_root": "/docs/csharp/programming-guide/classes-and-structs/structs.md", "redirect_url": "/dotnet/csharp/language-reference/builtin-types/struct" diff --git a/docs/core/compatibility/core-libraries/7.0/reflection-invoke-exceptions.md b/docs/core/compatibility/core-libraries/7.0/reflection-invoke-exceptions.md index e71d79e69896e..4dd0df9520b52 100644 --- a/docs/core/compatibility/core-libraries/7.0/reflection-invoke-exceptions.md +++ b/docs/core/compatibility/core-libraries/7.0/reflection-invoke-exceptions.md @@ -9,7 +9,7 @@ The exceptions thrown when calling reflection invoke APIs have changed. ## Previous behavior -- Previously, when an invoked method that [returns a value by reference](../../../../csharp/programming-guide/classes-and-structs/ref-returns.md) returned `null`, a was thrown. +- Previously, when an invoked method that [returns a value by reference](../../../../csharp/language-reference/statements/jump-statements.md#ref-returns) returned `null`, a was thrown. - For constructors, the following exceptions were thrown: diff --git a/docs/csharp/fundamentals/coding-style/coding-conventions.md b/docs/csharp/fundamentals/coding-style/coding-conventions.md index 718dfcf999533..0b0c32412ff13 100644 --- a/docs/csharp/fundamentals/coding-style/coding-conventions.md +++ b/docs/csharp/fundamentals/coding-style/coding-conventions.md @@ -186,7 +186,7 @@ The following sections describe practices that the C# team follows to prepare co :::code language="csharp" source="./snippets/coding-conventions/program.cs" id="Snippet8"::: -- Don't use [var](../../language-reference/keywords/var.md) when the type is not apparent from the right side of the assignment. Don't assume the type is clear from a method name. A variable type is considered clear if it's a `new` operator or an explicit cast. +- Don't use [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) when the type is not apparent from the right side of the assignment. Don't assume the type is clear from a method name. A variable type is considered clear if it's a `new` operator or an explicit cast. :::code language="csharp" source="./snippets/coding-conventions/program.cs" id="Snippet9"::: diff --git a/docs/csharp/fundamentals/object-oriented/index.md b/docs/csharp/fundamentals/object-oriented/index.md index d5c0a8e45c7e5..0104fc6592f2e 100644 --- a/docs/csharp/fundamentals/object-oriented/index.md +++ b/docs/csharp/fundamentals/object-oriented/index.md @@ -94,7 +94,7 @@ You can "extend" a class without creating a derived class by creating a separate ## Implicitly Typed Local Variables -Within a class or struct method, you can use implicit typing to instruct the compiler to determine a variable's type at compile time. For more information, see [var (C# reference)](../../language-reference/keywords/var.md). +Within a class or struct method, you can use implicit typing to instruct the compiler to determine a variable's type at compile time. For more information, see [var (C# reference)](../../language-reference/statements/declarations.md#implicitly-typed-local-variables). ## Records diff --git a/docs/csharp/fundamentals/types/anonymous-types.md b/docs/csharp/fundamentals/types/anonymous-types.md index 4e720611ad149..df7f853c0803a 100644 --- a/docs/csharp/fundamentals/types/anonymous-types.md +++ b/docs/csharp/fundamentals/types/anonymous-types.md @@ -37,7 +37,7 @@ If you don't specify member names in the anonymous type, the compiler gives the > [!TIP] > You can use .NET style rule [IDE0037](../../../fundamentals/code-analysis/style-rules/ide0037.md) to enforce whether inferred or explicit member names are preferred. -Typically, when you use an anonymous type to initialize a variable, you declare the variable as an implicitly typed local variable by using [var](../../language-reference/keywords/var.md). The type name cannot be specified in the variable declaration because only the compiler has access to the underlying name of the anonymous type. For more information about `var`, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md). +Typically, when you use an anonymous type to initialize a variable, you declare the variable as an implicitly typed local variable by using [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables). The type name cannot be specified in the variable declaration because only the compiler has access to the underlying name of the anonymous type. For more information about `var`, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md). You can create an array of anonymously typed elements by combining an implicitly typed local variable and an implicitly typed array, as shown in the following example. diff --git a/docs/csharp/fundamentals/types/index.md b/docs/csharp/fundamentals/types/index.md index 44df18e481a95..c80b9a27766d6 100644 --- a/docs/csharp/fundamentals/types/index.md +++ b/docs/csharp/fundamentals/types/index.md @@ -36,7 +36,7 @@ The compiler embeds the type information into the executable file as metadata. T ## Specifying types in variable declarations -When you declare a variable or constant in a program, you must either specify its type or use the [`var`](../../language-reference/keywords/var.md) keyword to let the compiler infer the type. The following example shows some variable declarations that use both built-in numeric types and complex user-defined types: +When you declare a variable or constant in a program, you must either specify its type or use the [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) keyword to let the compiler infer the type. The following example shows some variable declarations that use both built-in numeric types and complex user-defined types: :::code language="csharp" source="../../programming-guide/types/snippets/index/Program.cs" ID="Declarations"::: @@ -150,7 +150,7 @@ The use of the type parameter makes it possible to reuse the same class to hold ## Implicit types, anonymous types, and nullable value types -You can implicitly type a local variable (but not class members) by using the [`var`](../../language-reference/keywords/var.md) keyword. The variable still receives a type at compile time, but the type is provided by the compiler. For more information, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md). +You can implicitly type a local variable (but not class members) by using the [`var`](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) keyword. The variable still receives a type at compile time, but the type is provided by the compiler. For more information, see [Implicitly Typed Local Variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md). It can be inconvenient to create a named type for simple sets of related values that you don't intend to store or pass outside method boundaries. You can create *anonymous types* for this purpose. For more information, see [Anonymous Types](anonymous-types.md). diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index 75e2bbc4577bb..79827ab7a4f38 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -127,7 +127,7 @@ Structs have most of the capabilities of a [class](../keywords/class.md) type. T ## Passing structure-type variables by reference -When you pass a structure-type variable to a method as an argument or return a structure-type value from a method, the whole instance of a structure type is copied. Pass by value can affect the performance of your code in high-performance scenarios that involve large structure types. You can avoid value copying by passing a structure-type variable by reference. Use the [`ref`](../keywords/ref.md#passing-an-argument-by-reference), [`out`](../keywords/out-parameter-modifier.md), or [`in`](../keywords/in-parameter-modifier.md) method parameter modifiers to indicate that an argument must be passed by reference. Use [ref returns](../../programming-guide/classes-and-structs/ref-returns.md) to return a method result by reference. For more information, see [Write safe and efficient C# code](../../write-safe-efficient-code.md). +When you pass a structure-type variable to a method as an argument or return a structure-type value from a method, the whole instance of a structure type is copied. Pass by value can affect the performance of your code in high-performance scenarios that involve large structure types. You can avoid value copying by passing a structure-type variable by reference. Use the [`ref`](../keywords/ref.md#passing-an-argument-by-reference), [`out`](../keywords/out-parameter-modifier.md), or [`in`](../keywords/in-parameter-modifier.md) method parameter modifiers to indicate that an argument must be passed by reference. Use [ref returns](../statements/jump-statements.md#the-return-statement) to return a method result by reference. For more information, see [Write safe and efficient C# code](../../write-safe-efficient-code.md). ## struct constraint diff --git a/docs/csharp/language-reference/compiler-messages/cs1942.md b/docs/csharp/language-reference/compiler-messages/cs1942.md index 8759827e36736..404cbc20811ac 100644 --- a/docs/csharp/language-reference/compiler-messages/cs1942.md +++ b/docs/csharp/language-reference/compiler-messages/cs1942.md @@ -38,5 +38,5 @@ CS1942 is related to CS1949 because the use of `var` with a range variable cause ## See also -- [var](../keywords/var.md) +- [var](../statements/declarations.md#implicitly-typed-local-variables) - [LINQ in C#](../../linq/index.md) diff --git a/docs/csharp/language-reference/keywords/async.md b/docs/csharp/language-reference/keywords/async.md index ee930dc6ab064..904c4f7962fe7 100644 --- a/docs/csharp/language-reference/keywords/async.md +++ b/docs/csharp/language-reference/keywords/async.md @@ -72,7 +72,7 @@ An async method can have the following return types: - [void](../builtin-types/void.md). `async void` methods are generally discouraged for code other than event handlers because callers cannot `await` those methods and must implement a different mechanism to report successful completion or error conditions. - Starting with C# 7.0, any type that has an accessible `GetAwaiter` method. The `System.Threading.Tasks.ValueTask` type is one such implementation. It is available by adding the NuGet package `System.Threading.Tasks.Extensions`. -The async method can't declare any [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md) parameters, nor can it have a [reference return value](../../programming-guide/classes-and-structs/ref-returns.md), but it can call methods that have such parameters. +The async method can't declare any [in](./in-parameter-modifier.md), [ref](./ref.md) or [out](./out-parameter-modifier.md) parameters, nor can it have a [reference return value](../statements/jump-statements.md#ref-returns), but it can call methods that have such parameters. You specify `Task` as the return type of an async method if the [return](../statements/jump-statements.md#the-return-statement) statement of the method specifies an operand of type `TResult`. You use `Task` if no meaningful value is returned when the method is completed. That is, a call to the method returns a `Task`, but when the `Task` is completed, any `await` expression that's awaiting the `Task` evaluates to `void`. diff --git a/docs/csharp/language-reference/keywords/from-clause.md b/docs/csharp/language-reference/keywords/from-clause.md index 81bcc28d5fb24..4e1f584c0ecbe 100644 --- a/docs/csharp/language-reference/keywords/from-clause.md +++ b/docs/csharp/language-reference/keywords/from-clause.md @@ -20,7 +20,7 @@ A query expression must begin with a `from` clause. Additionally, a query expres Both the range variable and the data source are strongly typed. The data source referenced in the `from` clause must have a type of , , or a derived type such as . -In the following example, `numbers` is the data source and `num` is the range variable. Note that both variables are strongly typed even though the [var](var.md) keyword is used. +In the following example, `numbers` is the data source and `num` is the range variable. Note that both variables are strongly typed even though the [var](../statements//declarations.md#implicitly-typed-local-variables) keyword is used. [!code-csharp[cscsrefQueryKeywords#1](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsCsrefQueryKeywords/CS/From.cs#1)] diff --git a/docs/csharp/language-reference/keywords/index.md b/docs/csharp/language-reference/keywords/index.md index b6342a9da44e3..22904c0669112 100644 --- a/docs/csharp/language-reference/keywords/index.md +++ b/docs/csharp/language-reference/keywords/index.md @@ -156,7 +156,7 @@ A contextual keyword is used to provide a specific meaning in the code, but it i [`unmanaged` (function pointer calling convention)](../unsafe-code.md#function-pointers) [`unmanaged` (generic type constraint)](../../programming-guide/generics/constraints-on-type-parameters.md#unmanaged-constraint) [`value`](value.md) - [`var`](var.md) + [`var`](../statements/declarations.md#implicitly-typed-local-variables) [`when` (filter condition)](when.md) [`where` (generic type constraint)](where-generic-type-constraint.md) [`where` (query clause)](where-clause.md) diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index ee4ad8954dcbe..f4d8a18889b86 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -147,7 +147,7 @@ When the caller stores the value returned by the `GetBookByTitle` method as a re ## See also - [Write safe efficient code](../../write-safe-efficient-code.md) -- [Ref returns and ref locals](../../programming-guide/classes-and-structs/ref-returns.md) +- [Ref locals](../statements/declarations.md#ref-locals) - [Conditional ref expression](../operators/conditional-operator.md#conditional-ref-expression) - [Method Parameters](method-parameters.md) - [C# Reference](../index.md) diff --git a/docs/csharp/language-reference/keywords/var.md b/docs/csharp/language-reference/keywords/var.md deleted file mode 100644 index 5199b0d9bcbf8..0000000000000 --- a/docs/csharp/language-reference/keywords/var.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -description: "var - C# reference" -title: "var - C# reference" -ms.date: 09/02/2021 -f1_keywords: - - "var" - - "var_CSharpKeyword" -helpviewer_keywords: - - "var keyword [C#]" ---- -# var (C# reference) - -Beginning with C# 3, variables that are declared at method scope can have an implicit "type" `var`. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of `i` are functionally equivalent: - -```csharp -var i = 10; // Implicitly typed. -int i = 10; // Explicitly typed. -``` - -> [!IMPORTANT] -> When `var` is used with [nullable reference types](../builtin-types/nullable-reference-types.md) enabled, it always implies a nullable reference type even if the expression type isn't nullable. The compiler's null state analysis protects against dereferencing a potential `null` value. If the variable is never assigned to an expression that maybe null, the compiler won't emit any warnings. If you assign the variable to an expression that might be null, you must test that it isn't null before dereferencing it to avoid any warnings. - -A common use of the `var` keyword is with constructor invocation expressions. The use of `var` allows you to not repeat a type name in a variable declaration and object instantiation, as the following example shows: - -```csharp -var xs = new List(); -``` - -Beginning with C# 9.0, you can use a target-typed [`new` expression](../operators/new-operator.md) as an alternative: - -```csharp -List xs = new(); -List? ys = new(); -``` - -In pattern matching, the `var` keyword is used in a [`var` pattern](../operators/patterns.md#var-pattern). - -## Example - -The following example shows two query expressions. In the first expression, the use of `var` is permitted but is not required, because the type of the query result can be stated explicitly as an `IEnumerable`. However, in the second expression, `var` allows the result to be a collection of anonymous types, and the name of that type is not accessible except to the compiler itself. Use of `var` eliminates the requirement to create a new class for the result. Note that in Example #2, the `foreach` iteration variable `item` must also be implicitly typed. - -[!code-csharp[csrefKeywordsTypes#18](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs#18)] - -## See also - -- ['var' preferences (style rules IDE0007 and IDE0008)](../../../fundamentals/code-analysis/style-rules/ide0007-ide0008.md) -- [C# reference](../index.md) -- [Implicitly typed local variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md) -- [Type relationships in LINQ query operations](../../programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md) diff --git a/docs/csharp/language-reference/operators/conditional-operator.md b/docs/csharp/language-reference/operators/conditional-operator.md index 7f43b5941eb64..436bfe93ed0a2 100644 --- a/docs/csharp/language-reference/operators/conditional-operator.md +++ b/docs/csharp/language-reference/operators/conditional-operator.md @@ -29,7 +29,7 @@ Beginning with C# 9.0, conditional expressions are target-typed. That is, if a t [!code-csharp[target-typed conditional](snippets/shared/ConditionalOperator.cs#TargetTyped)] -If a target type of a conditional expression is unknown (for example, when you use the [`var`](../keywords/var.md) keyword) or in C# 8.0 and earlier, the type of `consequent` and `alternative` must be the same or there must be an implicit conversion from one type to the other: +If a target type of a conditional expression is unknown (for example, when you use the [`var`](../statements/declarations.md#implicitly-typed-local-variables) keyword) or in C# 8.0 and earlier, the type of `consequent` and `alternative` must be the same or there must be an implicit conversion from one type to the other: [!code-csharp[not target-typed conditional](snippets/shared/ConditionalOperator.cs#NotTargetTyped)] diff --git a/docs/csharp/language-reference/operators/new-operator.md b/docs/csharp/language-reference/operators/new-operator.md index c0f7aa91c5a46..f3291a0b0353d 100644 --- a/docs/csharp/language-reference/operators/new-operator.md +++ b/docs/csharp/language-reference/operators/new-operator.md @@ -30,7 +30,7 @@ Beginning with C# 9.0, constructor invocation expressions are target-typed. That As the preceding example shows, you always use parentheses in a target-typed `new` expression. -If a target type of a `new` expression is unknown (for example, when you use the [`var`](../keywords/var.md) keyword), you must specify a type name. +If a target type of a `new` expression is unknown (for example, when you use the [`var`](../statements/declarations.md#implicitly-typed-local-variables) keyword), you must specify a type name. ## Array creation diff --git a/docs/csharp/programming-guide/classes-and-structs/ref-returns.md b/docs/csharp/language-reference/statements/declarations.md similarity index 68% rename from docs/csharp/programming-guide/classes-and-structs/ref-returns.md rename to docs/csharp/language-reference/statements/declarations.md index 4be92730f1022..dac068ce72e3f 100644 --- a/docs/csharp/programming-guide/classes-and-structs/ref-returns.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -1,56 +1,67 @@ --- -title: "Ref return values and ref locals (C# Guide)" -description: "Learn how to define and use ref return and ref local values" -ms.date: "07/11/2021" +title: "Declaration statements - C# reference" +description: "Declaration statements, including `var`, `ref` locals, and `ref` fields - C# reference" +ms.date: 09/08/2022 +f1_keywords: + - "var" + - "var_CSharpKeyword" +helpviewer_keywords: + - "var keyword [C#]" --- -# Ref returns and ref locals +# Declaration statements -Starting with C# 7.0, C# supports reference return values (ref returns). A reference return value allows a method to return a reference to a variable, rather than a value, back to a caller. The caller can then choose to treat the returned variable as if it were returned by value or by reference. The caller can create a new variable that is itself a reference to the returned value, called a ref local. +A *declaration statement* declares a new variable, and optionally, initializes it. All variables have declared type. You can learn more about types in the article on the [.NET type system](../../../standard/base-types/common-type-system.md). -## What is a reference return value? +## Implicitly typed local variables -Most developers are familiar with passing an argument to a called method *by reference*. A called method's argument list includes a variable passed by reference. Any changes made to its value by the called method are observed by the caller. A *reference return value* means that a method returns a *reference* (or an alias) to some variable. That variable's scope must include the method. That variable's lifetime must extend beyond the return of the method. Modifications to the method's return value by the caller are made to the variable that is returned by the method. +Beginning with C# 3, variables that are declared at method scope can have an implicit "type" `var`. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of `i` are functionally equivalent: -Declaring that a method returns a *reference return value* indicates that the method returns an alias to a variable. The design intent is often that the calling code should have access to that variable through the alias, including to modify it. It follows that methods returning by reference can't have the return type `void`. +```csharp +var i = 10; // Implicitly typed. +int i = 10; // Explicitly typed. +``` -There are some restrictions on the expression that a method can return as a reference return value. Restrictions include: +> [!IMPORTANT] +> When `var` is used with [nullable reference types](../builtin-types/nullable-reference-types.md) enabled, it always implies a nullable reference type even if the expression type isn't nullable. The compiler's null state analysis protects against dereferencing a potential `null` value. If the variable is never assigned to an expression that maybe null, the compiler won't emit any warnings. If you assign the variable to an expression that might be null, you must test that it isn't null before dereferencing it to avoid any warnings. -- The return value must have a lifetime that extends beyond the execution of the method. In other words, it cannot be a local variable in the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Cannot return local 'obj' by reference because it is not a ref local." +A common use of the `var` keyword is with constructor invocation expressions. The use of `var` allows you to not repeat a type name in a variable declaration and object instantiation, as the following example shows: -- The return value cannot be the literal `null`. Returning `null` generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference." +```csharp +var xs = new List(); +``` - A method with a ref return can return an alias to a variable whose value is currently the null (uninstantiated) value or a [nullable value type](../../language-reference/builtin-types/nullable-value-types.md) for a value type. +Beginning with C# 9.0, you can use a target-typed [`new` expression](../operators/new-operator.md) as an alternative: -- The return value cannot be a constant, an enumeration member, the by-value return value from a property, or a method of a `class` or `struct`. Violating this rule generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference." +```csharp +List xs = new(); +List? ys = new(); +``` -In addition, reference return values are not allowed on async methods. An asynchronous method may return before it has finished execution, while its return value is still unknown. +In pattern matching, the `var` keyword is used in a [`var` pattern](../operators/patterns.md#var-pattern). + +The following example shows two query expressions. In the first expression, the use of `var` is permitted but is not required, because the type of the query result can be stated explicitly as an `IEnumerable`. However, in the second expression, `var` allows the result to be a collection of anonymous types, and the name of that type is not accessible except to the compiler itself. Use of `var` eliminates the requirement to create a new class for the result. Note that in Example #2, the `foreach` iteration variable `item` must also be implicitly typed. -## Defining a ref return value +[!code-csharp[csrefKeywordsTypes#18](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs#18)] -A method that returns a *reference return value* must satisfy the following two conditions: +## Ref returns and ref locals -- The method signature includes the [ref](../../language-reference/keywords/ref.md) keyword in front of the return type. -- Each [return](../../language-reference/statements/jump-statements.md#the-return-statement) statement in the method body includes the [ref](../../language-reference/keywords/ref.md) keyword in front of the name of the returned instance. +Starting with C# 7.0, C# supports reference return values (ref returns). A reference return value allows a method to return a reference to a variable, rather than a value, back to a caller. The caller can then choose to treat the returned variable as if it were returned by value or by reference. The caller can create a new variable that is itself a reference to the returned value, called a ref local. -The following example shows a method that satisfies those conditions and returns a reference to a `Person` object named `p`: +Most developers are familiar with passing an argument to a called method *by reference*. A called method's argument list includes a variable passed by reference. Any changes made to its value by the called method are observed by the caller. A *reference return value* means that a method returns a *reference* (or an alias) to some variable. That variable's scope must include the method. That variable's lifetime must extend beyond the return of the method. Modifications to the method's return value by the caller are made to the variable that is returned by the method. -```csharp -public ref Person GetContactInformation(string fname, string lname) -{ - // ...method implementation... - return ref p; -} -``` +Declaring that a method returns a *reference return value* indicates that the method returns an alias to a variable. The design intent is often that the calling code should have access to that variable through the alias, including to modify it. It follows that methods returning by reference can't have the return type `void`. + +There are some restrictions on the expression that a method can return as a reference return value. Restrictions include: -## Consuming a ref return value +- The return value must have a lifetime that extends beyond the execution of the method. In other words, it cannot be a local variable in the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Cannot return local 'obj' by reference because it is not a ref local." + +- The return value cannot be the literal `null`. Returning `null` generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference." + + A method with a ref return can return an alias to a variable whose value is currently the null (uninstantiated) value or a [nullable value type](../../language-reference/builtin-types/nullable-value-types.md) for a value type. -The ref return value is an alias to another variable in the called method's scope. You can interpret any use of the ref return as using the variable it aliases: +- The return value cannot be a constant, an enumeration member, the by-value return value from a property, or a method of a `class` or `struct`. Violating this rule generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference." -- When you assign its value, you are assigning a value to the variable it aliases. -- When you read its value, you are reading the value of the variable it aliases. -- If you return it *by reference*, you are returning an alias to that same variable. -- If you pass it to another method *by reference*, you are passing a reference to the variable it aliases. -- When you make a [ref local](#ref-locals) alias, you make a new alias to the same variable. +In addition, reference return values are not allowed on async methods. An asynchronous method may return before it has finished execution, while its return value is still unknown. ## Ref locals @@ -95,8 +106,6 @@ refLocal = ref anotherVeryLargeStruct; // reassigned, refLocal refers to differe Ref local variables must still be initialized when they are declared. -## Ref returns and ref locals: an example - The following example defines a `NumberStore` class that stores an array of integer values. The `FindNumber` method returns by reference the first number that is greater than or equal to the number passed as an argument. If no number is greater than or equal to the argument, the method returns the number in index 0. [!code-csharp[ref-returns](../../../../samples/snippets/csharp/programming-guide/ref-returns/NumberStore.cs#1)] @@ -119,3 +128,7 @@ closer to the end of the array, as the array is iterated from end towards the be - [ref keyword](../../language-reference/keywords/ref.md) - [Write safe efficient code](../../write-safe-efficient-code.md) +- ['var' preferences (style rules IDE0007 and IDE0008)](../../../fundamentals/code-analysis/style-rules/ide0007-ide0008.md) +- [C# reference](../index.md) +- [Implicitly typed local variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md) +- [Type relationships in LINQ query operations](../../programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md) diff --git a/docs/csharp/language-reference/statements/iteration-statements.md b/docs/csharp/language-reference/statements/iteration-statements.md index 58681965965df..0da808c6f0708 100644 --- a/docs/csharp/language-reference/statements/iteration-statements.md +++ b/docs/csharp/language-reference/statements/iteration-statements.md @@ -116,7 +116,7 @@ By default, stream elements are processed in the captured context. If you want t ### Type of an iteration variable -You can use the [`var` keyword](../keywords/var.md) to let the compiler infer the type of an iteration variable in the `foreach` statement, as the following code shows: +You can use the [`var` keyword](declarations.md#implicitly-typed-local-variables) to let the compiler infer the type of an iteration variable in the `foreach` statement, as the following code shows: ```csharp foreach (var item in collection) { } diff --git a/docs/csharp/language-reference/statements/jump-statements.md b/docs/csharp/language-reference/statements/jump-statements.md index 101ee8dce2ddd..1dd8a27cdc05c 100644 --- a/docs/csharp/language-reference/statements/jump-statements.md +++ b/docs/csharp/language-reference/statements/jump-statements.md @@ -1,7 +1,7 @@ --- title: "Jump statements - C# reference" description: "Learn about C# jump statements: break, continue, return, and goto." -ms.date: 12/08/2021 +ms.date: 09/08/2022 f1_keywords: - "break_CSharpKeyword" - "continue_CSharpKeyword" @@ -23,7 +23,7 @@ The following statements unconditionally transfer control: - The [`break` statement](#the-break-statement): terminates the closest enclosing [iteration statement](iteration-statements.md) or [`switch` statement](selection-statements.md#the-switch-statement). - The [`continue` statement](#the-continue-statement): starts a new iteration of the closest enclosing [iteration statement](iteration-statements.md). -- The [`return` statement](#the-return-statement): terminates execution of the function in which it appears and returns control to the caller. +- The [`return` statement](#the-return-statement): terminates execution of the function in which it appears and returns control to the caller. The `ref` modifier on a `return` statement indicates the returned expression is returned *by reference*, not *by value*. - The [`goto` statement](#the-goto-statement): transfers control to a statement that is marked by a label. For information about the `throw` statement that throws an exception and unconditionally transfers control as well, see [throw](../keywords/throw.md). @@ -62,13 +62,48 @@ If a function member computes a value, you use the `return` statement with an ex :::code language="csharp" interactive="try-dotnet-method" source="snippets/jump-statements/ReturnStatement.cs" id="WithExpression"::: -When the `return` statement has an expression, that expression must be implicitly convertible to the return type of a function member unless it's [async](../keywords/async.md). In the case of an `async` function, the expression must be implicitly convertible to the type argument of or , whichever is the return type of the function. If the return type of an `async` function is or , you use the `return` statement without expression. +When the `return` statement has an expression, that expression must be implicitly convertible to the return type of a function member unless it's [async](../keywords/async.md). The expression returned from an `async` function must be implicitly convertible to the type argument of or , whichever is the return type of the function. If the return type of an `async` function is or , you use the `return` statement without expression. By default, the `return` statement returns the value of an expression. Beginning with C# 7.0, you can return a reference to a variable. To do that, use the `return` statement with the [`ref` keyword](../keywords/ref.md), as the following example shows: :::code language="csharp" interactive="try-dotnet-method" source="snippets/jump-statements/ReturnStatement.cs" id="RefReturn"::: -For more information about ref returns, see [Ref returns and ref locals](../../programming-guide/classes-and-structs/ref-returns.md). +### Ref returns + +Beginning with C# 7.0, return values can be returned by reference (`ref` returns). A reference return value allows a method to return a reference to a variable, rather than a value, back to a caller. The caller can then choose to treat the returned variable as if it were returned by value or by reference. The caller can create a new variable that is itself a reference to the returned value, called a [ref local](declarations.md#ref-locals). A *reference return value* means that a method returns a *reference* (or an alias) to some variable. That variable's scope must include the method. That variable's lifetime must extend beyond the return of the method. Modifications to the method's return value by the caller are made to the variable that is returned by the method. + +Declaring that a method returns a *reference return value* indicates that the method returns an alias to a variable. The design intent is often that calling code accesses that variable through the alias, including to modify it. Methods returning by reference can't have the return type `void`. + +The `ref` return value is an alias to another variable in the called method's scope. You can interpret any use of the ref return as using the variable it aliases: + +- When you assign its value, you're assigning a value to the variable it aliases. +- When you read its value, you're reading the value of the variable it aliases. +- If you return it *by reference*, you're returning an alias to that same variable. +- If you pass it to another method *by reference*, you're passing a reference to the variable it aliases. +- When you make a [ref local](declarations.md#ref-locals) alias, you make a new alias to the same variable. + +A ref return must be [*ref_safe_to_escape*](../keywords/method-parameters.md#scope-of-references-and-values) to the calling method. That means: + +- The return value must have a lifetime that extends beyond the execution of the method. In other words, it can't be a local variable in the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Can't return local 'obj' by reference because it isn't a ref local." +- The return value can't be the literal `null`. A method with a ref return can return an alias to a variable whose value is currently the `null` (uninstantiated) value or a [nullable value type](../../language-reference/builtin-types/nullable-value-types.md) for a value type. +- The return value can't be a constant, an enumeration member, the by-value return value from a property, or a method of a `class` or `struct`. + +In addition, reference return values aren't allowed on async methods. An asynchronous method may return before it has finished execution, while its return value is still unknown. + +A method that returns a *reference return value* must: + +- Include the [ref](../../language-reference/keywords/ref.md) keyword in front of the return type. +- Each [return](../../language-reference/statements/jump-statements.md#the-return-statement) statement in the method body includes the [ref](../../language-reference/keywords/ref.md) keyword in front of the name of the returned instance. + +The following example shows a method that satisfies those conditions and returns a reference to a `Person` object named `p`: + +```csharp +public ref Person GetContactInformation(string fname, string lname) +{ + // ...method implementation... + return ref p; +} +``` ## The `goto` statement @@ -87,7 +122,7 @@ You can also use the `goto` statement in the [`switch` statement](selection-stat Within the `switch` statement, you can also use the statement `goto default;` to transfer control to the switch section with the `default` label. -If a label with the given name doesn't exist in the current function member, or if the `goto` statement is not within the scope of the label, a compile-time error occurs. That is, you can't use the `goto` statement to transfer control out of the current function member or into any nested scope, for example, a `try` block. +If a label with the given name doesn't exist in the current function member, or if the `goto` statement isn't within the scope of the label, a compile-time error occurs. That is, you can't use the `goto` statement to transfer control out of the current function member or into any nested scope, for example, a `try` block. ## C# language specification diff --git a/docs/csharp/linq/query-expression-basics.md b/docs/csharp/linq/query-expression-basics.md index 3fe8e7574f076..13abf69f57153 100644 --- a/docs/csharp/linq/query-expression-basics.md +++ b/docs/csharp/linq/query-expression-basics.md @@ -72,7 +72,7 @@ For more information about the different ways to express queries, see [Query syn #### Explicit and implicit typing of query variables -This documentation usually provides the explicit type of the query variable in order to show the type relationship between the query variable and the [select clause](../language-reference/keywords/select-clause.md). However, you can also use the [var](../language-reference/keywords/var.md) keyword to instruct the compiler to infer the type of a query variable (or any other local variable) at compile time. For example, the query example that was shown previously in this topic can also be expressed by using implicit typing: +This documentation usually provides the explicit type of the query variable in order to show the type relationship between the query variable and the [select clause](../language-reference/keywords/select-clause.md). However, you can also use the [var](../language-reference/statements/declarations.md#implicitly-typed-local-variables) keyword to instruct the compiler to infer the type of a query variable (or any other local variable) at compile time. For example, the query example that was shown previously in this topic can also be expressed by using implicit typing: :::code language="csharp" source="../../../samples/snippets/csharp/concepts/linq/LinqSamples/Basics.cs" id="basics8"::: diff --git a/docs/csharp/linq/write-linq-queries.md b/docs/csharp/linq/write-linq-queries.md index a216cf3018d8b..dd9e333283712 100644 --- a/docs/csharp/linq/write-linq-queries.md +++ b/docs/csharp/linq/write-linq-queries.md @@ -43,7 +43,7 @@ If the method has Action or Func parameters, these are provided in the form of a In the previous queries, only Query #4 executes immediately. This is because it returns a single value, and not a generic collection. The method itself has to use `foreach` in order to compute its value. -Each of the previous queries can be written by using implicit typing with [var](../language-reference/keywords/var.md), as shown in the following example: +Each of the previous queries can be written by using implicit typing with [var](../language-reference/statements/declarations.md#implicitly-typed-local-variables), as shown in the following example: :::code language="csharp" source="../../../samples/snippets/csharp/concepts/linq/LinqSamples/WriteLinqQueries.cs" id="write_linq_queries_4"::: diff --git a/docs/csharp/misc/cs1949.md b/docs/csharp/misc/cs1949.md index 997aab5acc94d..cace63f2d79e0 100644 --- a/docs/csharp/misc/cs1949.md +++ b/docs/csharp/misc/cs1949.md @@ -12,7 +12,7 @@ ms.assetid: 959f553e-ac3d-43a1-b0a0-11e270f2ad64 The contextual keyword 'var' cannot be used in a range variable declaration. - A range variable is implicitly typed by the compiler. There is no need to use [var](../language-reference/keywords/var.md) with a range variable. + A range variable is implicitly typed by the compiler. There is no need to use [var](../language-reference/statements/declarations.md#implicitly-typed-local-variables) with a range variable. ## To correct this error diff --git a/docs/csharp/programming-guide/arrays/implicitly-typed-arrays.md b/docs/csharp/programming-guide/arrays/implicitly-typed-arrays.md index 3a676a1157273..fcde97c577b91 100644 --- a/docs/csharp/programming-guide/arrays/implicitly-typed-arrays.md +++ b/docs/csharp/programming-guide/arrays/implicitly-typed-arrays.md @@ -34,5 +34,5 @@ When you create an anonymous type that contains an array, the array must be impl - [Arrays](./index.md) - [Anonymous Types](../../fundamentals/types/anonymous-types.md) - [Object and Collection Initializers](../classes-and-structs/object-and-collection-initializers.md) -- [var](../../language-reference/keywords/var.md) +- [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) - [LINQ in C#](../../linq/index.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md b/docs/csharp/programming-guide/classes-and-structs/how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md index 9bbd9368add96..5eceb4bfb95f7 100644 --- a/docs/csharp/programming-guide/classes-and-structs/how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md +++ b/docs/csharp/programming-guide/classes-and-structs/how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md @@ -12,7 +12,7 @@ ms.assetid: 6b7354d2-af79-427a-b6a8-f74eb8fd0b91 You can use implicitly typed local variables whenever you want the compiler to determine the type of a local variable. You must use implicitly typed local variables to store anonymous types, which are often used in query expressions. The following examples illustrate both optional and required uses of implicitly typed local variables in queries. - Implicitly typed local variables are declared by using the [var](../../language-reference/keywords/var.md) contextual keyword. For more information, see [Implicitly Typed Local Variables](./implicitly-typed-local-variables.md) and [Implicitly Typed Arrays](../arrays/implicitly-typed-arrays.md). + Implicitly typed local variables are declared by using the [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) contextual keyword. For more information, see [Implicitly Typed Local Variables](./implicitly-typed-local-variables.md) and [Implicitly Typed Arrays](../arrays/implicitly-typed-arrays.md). ## Examples @@ -29,5 +29,4 @@ You can use implicitly typed local variables whenever you want the compiler to d - [C# Programming Guide](../index.md) - [Extension Methods](./extension-methods.md) - [LINQ (Language-Integrated Query)](../../linq/index.md) -- [var](../../language-reference/keywords/var.md) - [LINQ in C#](../../linq/index.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md b/docs/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md index 18ab7f5948df6..5765045591d26 100644 --- a/docs/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md +++ b/docs/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md @@ -92,7 +92,7 @@ The use of `var` helps simplify your code, but its use should be restricted to c - [How to use implicitly typed local variables and arrays in a query expression](how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md) - [Anonymous Types](../../fundamentals/types/anonymous-types.md) - [Object and Collection Initializers](object-and-collection-initializers.md) -- [var](../../language-reference/keywords/var.md) +- [var](../../language-reference/statements/declarations.md#implicitly-typed-local-variables) - [LINQ in C#](../../linq/index.md) - [LINQ (Language-Integrated Query)](../../linq/index.md) - [Iteration statements](../../language-reference/statements/iteration-statements.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/methods.md b/docs/csharp/programming-guide/classes-and-structs/methods.md index 8ca12fdd6d71e..e8b971747a96c 100644 --- a/docs/csharp/programming-guide/classes-and-structs/methods.md +++ b/docs/csharp/programming-guide/classes-and-structs/methods.md @@ -61,7 +61,7 @@ For more information about how to pass reference types by reference and by value Methods can return a value to the caller. If the return type (the type listed before the method name) is not `void`, the method can return the value by using the [`return` statement](../../language-reference/statements/jump-statements.md#the-return-statement). A statement with the `return` keyword followed by a value that matches the return type will return that value to the method caller. -The value can be returned to the caller by value or, starting with C# 7.0, [by reference](ref-returns.md). Values are returned to the caller by reference if the `ref` keyword is used in the method signature and it follows each `return` keyword. For example, the following method signature and return statement indicate that the method returns a variable named `estDistance` by reference to the caller. +The value can be returned to the caller by value or, starting with C# 7.0, [by reference](../../language-reference/statements/jump-statements.md#ref-returns). Values are returned to the caller by reference if the `ref` keyword is used in the method signature and it follows each `return` keyword. For example, the following method signature and return statement indicate that the method returns a variable named `estDistance` by reference to the caller. ```csharp public ref double GetEstimatedDistance() @@ -82,7 +82,7 @@ To use a value returned from a method, the calling method can use the method cal Using a local variable, in this case, `result`, to store a value is optional. It may help the readability of the code, or it may be necessary if you need to store the original value of the argument for the entire scope of the method. -To use a value returned by reference from a method, you must declare a [ref local](ref-returns.md#ref-locals) variable if you intend to modify its value. For example, if the `Planet.GetEstimatedDistance` method returns a value by reference, you can define it as a ref local variable with code like the following: +To use a value returned by reference from a method, you must declare a [ref local](../../language-reference/statements/declarations.md#ref-locals) variable if you intend to modify its value. For example, if the `Planet.GetEstimatedDistance` method returns a value by reference, you can define it as a ref local variable with code like the following: ```csharp ref int distance = Planet.GetEstimatedDistance(); diff --git a/docs/csharp/programming-guide/concepts/linq/features-that-support-linq.md b/docs/csharp/programming-guide/concepts/linq/features-that-support-linq.md index 7205fe74262a7..7052aaa5ed4fb 100644 --- a/docs/csharp/programming-guide/concepts/linq/features-that-support-linq.md +++ b/docs/csharp/programming-guide/concepts/linq/features-that-support-linq.md @@ -25,7 +25,7 @@ For more information, see [LINQ Query Expressions](../../../linq/index.md). ## Implicitly Typed Variables (var) -Instead of explicitly specifying a type when you declare and initialize a variable, you can use the [var](../../../language-reference/keywords/var.md) modifier to instruct the compiler to infer and assign the type, as shown here: +Instead of explicitly specifying a type when you declare and initialize a variable, you can use the [var](../../../language-reference/statements/declarations.md#implicitly-typed-local-variables) modifier to instruct the compiler to infer and assign the type, as shown here: ```csharp var number = 5; diff --git a/docs/csharp/programming-guide/concepts/linq/linq-and-generic-types.md b/docs/csharp/programming-guide/concepts/linq/linq-and-generic-types.md index f239e09c41ef6..122f213813a50 100644 --- a/docs/csharp/programming-guide/concepts/linq/linq-and-generic-types.md +++ b/docs/csharp/programming-guide/concepts/linq/linq-and-generic-types.md @@ -28,7 +28,7 @@ LINQ queries are based on generic types, which were introduced in version 2.0 of ## Letting the Compiler Handle Generic Type Declarations - If you prefer, you can avoid generic syntax by using the [var](../../../language-reference/keywords/var.md) keyword. The `var` keyword instructs the compiler to infer the type of a query variable by looking at the data source specified in the `from` clause. The following example produces the same compiled code as the previous example: + If you prefer, you can avoid generic syntax by using the [var](../../../language-reference/statements/declarations.md#implicitly-typed-local-variables) keyword. The `var` keyword instructs the compiler to infer the type of a query variable by looking at the data source specified in the `from` clause. The following example produces the same compiled code as the previous example: [!code-csharp[csLINQGettingStarted#35](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsLINQGettingStarted/CS/Class1.cs#35)] diff --git a/docs/csharp/programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md b/docs/csharp/programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md index 7315cbbedf4a1..cc036174cd335 100644 --- a/docs/csharp/programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md +++ b/docs/csharp/programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md @@ -20,7 +20,7 @@ To write queries effectively, you should understand how types of the variables i LINQ query operations are strongly typed in the data source, in the query itself, and in the query execution. The type of the variables in the query must be compatible with the type of the elements in the data source and with the type of the iteration variable in the `foreach` statement. This strong typing guarantees that type errors are caught at compile time when they can be corrected before users encounter them. - In order to demonstrate these type relationships, most of the examples that follow use explicit typing for all variables. The last example shows how the same principles apply even when you use implicit typing by using [var](../../../language-reference/keywords/var.md). + In order to demonstrate these type relationships, most of the examples that follow use explicit typing for all variables. The last example shows how the same principles apply even when you use implicit typing by using [var](../../../language-reference/statements/declarations.md#implicitly-typed-local-variables). ## Queries that do not Transform the Source Data @@ -58,7 +58,7 @@ To write queries effectively, you should understand how types of the variables i ## Letting the compiler infer type information - Although you should understand the type relationships in a query operation, you have the option to let the compiler do all the work for you. The keyword [var](../../../language-reference/keywords/var.md) can be used for any local variable in a query operation. The following illustration is similar to example number 2 that was discussed earlier. However, the compiler supplies the strong type for each variable in the query operation. + Although you should understand the type relationships in a query operation, you have the option to let the compiler do all the work for you. The keyword [var](../../../language-reference/statements/declarations.md#implicitly-typed-local-variables) can be used for any local variable in a query operation. The following illustration is similar to example number 2 that was discussed earlier. However, the compiler supplies the strong type for each variable in the query operation. ![Diagram that shows the type flow with implicit typing.](./media/type-relationships-in-linq-query-operations/linq-type-flow-implicit-typing.png) diff --git a/docs/csharp/programming-guide/concepts/linq/walkthrough-writing-queries-linq.md b/docs/csharp/programming-guide/concepts/linq/walkthrough-writing-queries-linq.md index 781e34ac28137..7cdec326b46b2 100644 --- a/docs/csharp/programming-guide/concepts/linq/walkthrough-writing-queries-linq.md +++ b/docs/csharp/programming-guide/concepts/linq/walkthrough-writing-queries-linq.md @@ -61,7 +61,7 @@ This walkthrough demonstrates the C# language features that are used to write LI #### To create a simple query -- In the application's `Main` method, create a simple query that, when it is executed, will produce a list of all students whose score on the first test was greater than 90. Note that because the whole `Student` object is selected, the type of the query is `IEnumerable`. Although the code could also use implicit typing by using the [var](../../../language-reference/keywords/var.md) keyword, explicit typing is used to clearly illustrate results. (For more information about `var`, see [Implicitly Typed Local Variables](../../classes-and-structs/implicitly-typed-local-variables.md).) +- In the application's `Main` method, create a simple query that, when it is executed, will produce a list of all students whose score on the first test was greater than 90. Note that because the whole `Student` object is selected, the type of the query is `IEnumerable`. Although the code could also use implicit typing by using the [var](../../../language-reference/statements/declarations.md#implicitly-typed-local-variables) keyword, explicit typing is used to clearly illustrate results. (For more information about `var`, see [Implicitly Typed Local Variables](../../classes-and-structs/implicitly-typed-local-variables.md).) Note also that the query's range variable, `student`, serves as a reference to each `Student` in the source, providing member access for each object. @@ -135,7 +135,7 @@ This walkthrough demonstrates the C# language features that are used to write LI [!code-csharp[CsLINQGettingStarted#16](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsLINQGettingStarted/CS/Class1.cs#16)] - For more information about [var](../../../language-reference/keywords/var.md), see [Implicitly Typed Local Variables](../../classes-and-structs/implicitly-typed-local-variables.md). + For more information about [var](../../../language-reference/statements/declarations.md#implicitly-typed-local-variables), see [Implicitly Typed Local Variables](../../classes-and-structs/implicitly-typed-local-variables.md). #### To order the groups by their key value diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 67feb28d3c15a..e95bd0e80d34e 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -664,8 +664,6 @@ items: href: programming-guide/classes-and-structs/methods.md - name: Local functions href: programming-guide/classes-and-structs/local-functions.md - - name: Ref returns and ref locals - href: programming-guide/classes-and-structs/ref-returns.md - name: Implicitly Typed Local Variables href: programming-guide/classes-and-structs/implicitly-typed-local-variables.md - name: "How to use implicitly typed local variables and arrays in a query expression" @@ -902,8 +900,6 @@ items: displayName: "? token, ? symbol" - name: void href: language-reference/builtin-types/void.md - - name: var - href: language-reference/keywords/var.md - name: Built-in types href: language-reference/builtin-types/built-in-types.md - name: Unmanaged types @@ -1186,6 +1182,9 @@ items: href: language-reference/operators/operator-overloading.md - name: Statements items: + - name: Declaration statements + displayName: var, ref + href: language-reference/statements/declarations.md - name: Iteration statements displayName: for, foreach, do, while, loop href: language-reference/statements/iteration-statements.md diff --git a/docs/csharp/tutorials/console-teleprompter.md b/docs/csharp/tutorials/console-teleprompter.md index 86c5e95389096..17b21141f0bdf 100644 --- a/docs/csharp/tutorials/console-teleprompter.md +++ b/docs/csharp/tutorials/console-teleprompter.md @@ -72,7 +72,7 @@ more [`yield return`](../language-reference/keywords/yield.md) statements. The o There are two C# syntax elements that may be new to you. The [`using`](../language-reference/keywords/using-statement.md) statement in this method manages resource cleanup. The variable that is initialized in the `using` statement (`reader`, in this example) must implement the interface. That interface defines a single method, `Dispose`, that should be called when the resource should be released. The compiler generates that call when execution reaches the closing brace of the `using` statement. The compiler-generated code ensures that the resource is released even if an exception is thrown from the code in the block defined by the using statement. -The `reader` variable is defined using the `var` keyword. [`var`](../language-reference/keywords/var.md) defines an *implicitly typed local variable*. That means the type of the variable is determined by the compile-time type of the object assigned to the variable. Here, that is the return value from the method, which is a object. +The `reader` variable is defined using the `var` keyword. [`var`](../language-reference/statements/declarations.md#implicitly-typed-local-variables) defines an *implicitly typed local variable*. That means the type of the variable is determined by the compile-time type of the object assigned to the variable. Here, that is the return value from the method, which is a object. Now, let's fill in the code to read the file in the `Main` method: diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index d67dda6415670..a455d8cc97d4f 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -73,7 +73,7 @@ C# version 3.0 came in late 2007, along with Visual Studio 2008, though the full - [Lambda expressions](../language-reference/operators/lambda-expressions.md) - [Expression trees](../expression-trees.md) - [Extension methods](../programming-guide/classes-and-structs/extension-methods.md) -- [Implicitly typed local variables](../language-reference/keywords/var.md) +- [Implicitly typed local variables](../language-reference/statements/declarations.md#implicitly-typed-local-variables) - [Partial methods](../language-reference/keywords/partial-method.md) - [Object and collection initializers](../programming-guide/classes-and-structs/object-and-collection-initializers.md) @@ -148,7 +148,8 @@ C# version 7.0 was released with Visual Studio 2017. This version has some evolu - [Pattern matching](../fundamentals/functional/pattern-matching.md) - Local functions - Expanded expression bodied members -- [Ref locals and returns](../programming-guide/classes-and-structs/ref-returns.md) +- [Ref locals](../language-reference/statements/declarations.md#ref-locals) +- [Ref returns](../language-reference/statements/jump-statements.md#ref-returns) Other features included: diff --git a/docs/csharp/write-safe-efficient-code.md b/docs/csharp/write-safe-efficient-code.md index 51ae4d3e09d0d..8f069380d7f5c 100644 --- a/docs/csharp/write-safe-efficient-code.md +++ b/docs/csharp/write-safe-efficient-code.md @@ -297,4 +297,5 @@ These enhancements to the C# language are designed for performance critical algo - [in parameter modifier (C# Reference)](language-reference/keywords/in-parameter-modifier.md) - [ref keyword](language-reference/keywords/ref.md) -- [Ref returns and ref locals](programming-guide/classes-and-structs/ref-returns.md) +- [Ref returns](language-reference/statements/jump-statements.md#ref-returns) +- [Ref locals](language-reference/statements/declarations.md#ref-locals) diff --git a/docs/framework/whats-new/index.md b/docs/framework/whats-new/index.md index c578d291bfbf1..5c4db9a75d326 100644 --- a/docs/framework/whats-new/index.md +++ b/docs/framework/whats-new/index.md @@ -677,7 +677,7 @@ Starting with .NET Framework 4.7.1, . This attribute is used by language compilers to mark members that have read-only ref return types or parameters. For more information, see "Compiler -- Support for ReadOnlyReferences" in the [.NET Framework 4.7.1 Runtime and Compiler Features](https://devblogs.microsoft.com/dotnet/net-framework-4-7-1-runtime-and-compiler-features/) blog post. For information on ref return values, see [Ref return values and ref locals (C# Guide)](../../csharp/programming-guide/classes-and-structs/ref-returns.md) and [Ref return values (Visual Basic)](../../visual-basic/programming-guide/language-features/procedures/ref-return-values.md). +.NET Framework 4.7.1 adds the . This attribute is used by language compilers to mark members that have read-only ref return types or parameters. For more information, see "Compiler -- Support for ReadOnlyReferences" in the [.NET Framework 4.7.1 Runtime and Compiler Features](https://devblogs.microsoft.com/dotnet/net-framework-4-7-1-runtime-and-compiler-features/) blog post. For information on ref return values, see [Ref return values](../../csharp/language-reference/statements/jump-statements.md#ref-returns) and [ref locals](../../csharp/language-reference/statements/declarations.md#ref-locals) and [Ref return values (Visual Basic)](../../visual-basic/programming-guide/language-features/procedures/ref-return-values.md). diff --git a/docs/fundamentals/code-analysis/style-rules/ide0007-ide0008.md b/docs/fundamentals/code-analysis/style-rules/ide0007-ide0008.md index 07d0bae595680..cf0f093d45f6f 100644 --- a/docs/fundamentals/code-analysis/style-rules/ide0007-ide0008.md +++ b/docs/fundamentals/code-analysis/style-rules/ide0007-ide0008.md @@ -48,7 +48,7 @@ This article describes two related rules, `IDE0007` and `IDE0008`. ## Overview -These two style rules define whether the [var](../../../csharp/language-reference/keywords/var.md) keyword or an explicit type should be used in a variable declaration. To enforce that `var` is used, set the severity of `IDE0007` to warning or error. To enforce that the explicit type is used, set the severity of `IDE0008` to warning or error. +These two style rules define whether the [var](../../../csharp/language-reference/statements/declarations.md#implicitly-typed-local-variables) keyword or an explicit type should be used in a variable declaration. To enforce that `var` is used, set the severity of `IDE0007` to warning or error. To enforce that the explicit type is used, set the severity of `IDE0008` to warning or error. ## Options @@ -140,6 +140,6 @@ For more information, see [How to suppress code analysis warnings](../suppress-w ## See also -- [var keyword](../../../csharp/language-reference/keywords/var.md) +- [var keyword](../../../csharp/language-reference/statements/declarations.md#implicitly-typed-local-variables) - [Code style language rules](language-rules.md) - [Code style rules reference](index.md) From 8a107d73454879b68e17846f68bc3c0b3c2b29c5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 14 Sep 2022 14:00:23 -0400 Subject: [PATCH 06/16] move declaration samples Move all samples from the /samples/snippets folder under the current folder. --- .../statements/declarations.md | 33 +++---------- .../snippets/declarations/ImplicitlyTyped.cs | 45 ++++++++++++++++++ .../snippets/declarations}/NumberStore.cs | 0 .../declarations}/NumberStoreUpdated.cs | 0 .../snippets/declarations/Program.cs | 9 ++++ .../snippets/declarations/declarations.csproj | 10 ++++ .../csrefKeywordsTypes/CS/keywordsTypes.cs | 46 ------------------- .../programming-guide/ref-returns/Program.cs | 16 ------- .../ref-returns/ref-returns.csproj | 10 ---- 9 files changed, 70 insertions(+), 99 deletions(-) create mode 100644 docs/csharp/language-reference/statements/snippets/declarations/ImplicitlyTyped.cs rename {samples/snippets/csharp/programming-guide/ref-returns => docs/csharp/language-reference/statements/snippets/declarations}/NumberStore.cs (100%) rename {samples/snippets/csharp/programming-guide/ref-returns => docs/csharp/language-reference/statements/snippets/declarations}/NumberStoreUpdated.cs (100%) create mode 100644 docs/csharp/language-reference/statements/snippets/declarations/Program.cs create mode 100644 docs/csharp/language-reference/statements/snippets/declarations/declarations.csproj delete mode 100644 samples/snippets/csharp/programming-guide/ref-returns/Program.cs delete mode 100644 samples/snippets/csharp/programming-guide/ref-returns/ref-returns.csproj diff --git a/docs/csharp/language-reference/statements/declarations.md b/docs/csharp/language-reference/statements/declarations.md index dac068ce72e3f..95d2b423917d2 100644 --- a/docs/csharp/language-reference/statements/declarations.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -41,31 +41,11 @@ In pattern matching, the `var` keyword is used in a [`var` pattern](../operators The following example shows two query expressions. In the first expression, the use of `var` is permitted but is not required, because the type of the query result can be stated explicitly as an `IEnumerable`. However, in the second expression, `var` allows the result to be a collection of anonymous types, and the name of that type is not accessible except to the compiler itself. Use of `var` eliminates the requirement to create a new class for the result. Note that in Example #2, the `foreach` iteration variable `item` must also be implicitly typed. -[!code-csharp[csrefKeywordsTypes#18](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs#18)] - -## Ref returns and ref locals - -Starting with C# 7.0, C# supports reference return values (ref returns). A reference return value allows a method to return a reference to a variable, rather than a value, back to a caller. The caller can then choose to treat the returned variable as if it were returned by value or by reference. The caller can create a new variable that is itself a reference to the returned value, called a ref local. - -Most developers are familiar with passing an argument to a called method *by reference*. A called method's argument list includes a variable passed by reference. Any changes made to its value by the called method are observed by the caller. A *reference return value* means that a method returns a *reference* (or an alias) to some variable. That variable's scope must include the method. That variable's lifetime must extend beyond the return of the method. Modifications to the method's return value by the caller are made to the variable that is returned by the method. - -Declaring that a method returns a *reference return value* indicates that the method returns an alias to a variable. The design intent is often that the calling code should have access to that variable through the alias, including to modify it. It follows that methods returning by reference can't have the return type `void`. - -There are some restrictions on the expression that a method can return as a reference return value. Restrictions include: - -- The return value must have a lifetime that extends beyond the execution of the method. In other words, it cannot be a local variable in the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Cannot return local 'obj' by reference because it is not a ref local." - -- The return value cannot be the literal `null`. Returning `null` generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference." - - A method with a ref return can return an alias to a variable whose value is currently the null (uninstantiated) value or a [nullable value type](../../language-reference/builtin-types/nullable-value-types.md) for a value type. - -- The return value cannot be a constant, an enumeration member, the by-value return value from a property, or a method of a `class` or `struct`. Violating this rule generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference." - -In addition, reference return values are not allowed on async methods. An asynchronous method may return before it has finished execution, while its return value is still unknown. +:::code language="csharp" source="./snippets/declarations/ImplicitlyTyped.cs" id="VarExample"::: ## Ref locals -Assume the `GetContactInformation` method is declared as a ref return: +Assume the `GetContactInformation` method is declared as a [ref return](jump-statements.md#ref-returns): ```csharp public ref Person GetContactInformation(string fname, string lname) @@ -108,27 +88,26 @@ refLocal = ref anotherVeryLargeStruct; // reassigned, refLocal refers to differe The following example defines a `NumberStore` class that stores an array of integer values. The `FindNumber` method returns by reference the first number that is greater than or equal to the number passed as an argument. If no number is greater than or equal to the argument, the method returns the number in index 0. -[!code-csharp[ref-returns](../../../../samples/snippets/csharp/programming-guide/ref-returns/NumberStore.cs#1)] +:::code language="csharp" source="./snippets/declarations/NumberStore.cs" id="Snippet1"::: The following example calls the `NumberStore.FindNumber` method to retrieve the first value that is greater than or equal to 16. The caller then doubles the value returned by the method. The output from the example shows the change reflected in the value of the array elements of the `NumberStore` instance. -[!code-csharp[ref-returns](../../../../samples/snippets/csharp/programming-guide/ref-returns/NumberStore.cs#2)] +:::code language="csharp" source="./snippets/declarations/NumberStore.cs" id="Snippet2"::: Without support for reference return values, such an operation is performed by returning the index of the array element along with its value. The caller can then use this index to modify the value in a separate method call. However, the caller can also modify the index to access and possibly modify other array values. The following example shows how the `FindNumber` method could be rewritten after C# 7.3 to use ref local reassignment: -[!code-csharp[ref-returns](../../../../samples/snippets/csharp/programming-guide/ref-returns/NumberStoreUpdated.cs#1)] +:::code language="csharp" source="./snippets/declarations/NumberStoreUpdated.cs" id="Snippet1"::: This second version is more efficient with longer sequences in scenarios where the number sought is closer to the end of the array, as the array is iterated from end towards the beginning, causing fewer items to be examined. ## See also -- [ref keyword](../../language-reference/keywords/ref.md) +- [ref keyword](../keywords/ref.md) - [Write safe efficient code](../../write-safe-efficient-code.md) - ['var' preferences (style rules IDE0007 and IDE0008)](../../../fundamentals/code-analysis/style-rules/ide0007-ide0008.md) - [C# reference](../index.md) -- [Implicitly typed local variables](../../programming-guide/classes-and-structs/implicitly-typed-local-variables.md) - [Type relationships in LINQ query operations](../../programming-guide/concepts/linq/type-relationships-in-linq-query-operations.md) diff --git a/docs/csharp/language-reference/statements/snippets/declarations/ImplicitlyTyped.cs b/docs/csharp/language-reference/statements/snippets/declarations/ImplicitlyTyped.cs new file mode 100644 index 0000000000000..b31340141b277 --- /dev/null +++ b/docs/csharp/language-reference/statements/snippets/declarations/ImplicitlyTyped.cs @@ -0,0 +1,45 @@ + +namespace ImplicitTypes; + +class Customer +{ + public string City { get; set; } + public string Name { get; set; } + public string Phone { get; set; } +} + +public static class VarExample +{ + public static void ImplicitlyTyped() + { + List customers = new List(); + // + // Example #1: var is optional when + // the select clause specifies a string + string[] words = { "apple", "strawberry", "grape", "peach", "banana" }; + var wordQuery = from word in words + where word[0] == 'g' + select word; + + // Because each element in the sequence is a string, + // not an anonymous type, var is optional here also. + foreach (string s in wordQuery) + { + Console.WriteLine(s); + } + + // Example #2: var is required because + // the select clause specifies an anonymous type + var custQuery = from cust in customers + where cust.City == "Phoenix" + select new { cust.Name, cust.Phone }; + + // var must be used because each item + // in the sequence is an anonymous type + foreach (var item in custQuery) + { + Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone); + } + // + } +} diff --git a/samples/snippets/csharp/programming-guide/ref-returns/NumberStore.cs b/docs/csharp/language-reference/statements/snippets/declarations/NumberStore.cs similarity index 100% rename from samples/snippets/csharp/programming-guide/ref-returns/NumberStore.cs rename to docs/csharp/language-reference/statements/snippets/declarations/NumberStore.cs diff --git a/samples/snippets/csharp/programming-guide/ref-returns/NumberStoreUpdated.cs b/docs/csharp/language-reference/statements/snippets/declarations/NumberStoreUpdated.cs similarity index 100% rename from samples/snippets/csharp/programming-guide/ref-returns/NumberStoreUpdated.cs rename to docs/csharp/language-reference/statements/snippets/declarations/NumberStoreUpdated.cs diff --git a/docs/csharp/language-reference/statements/snippets/declarations/Program.cs b/docs/csharp/language-reference/statements/snippets/declarations/Program.cs new file mode 100644 index 0000000000000..562006d3e09ec --- /dev/null +++ b/docs/csharp/language-reference/statements/snippets/declarations/Program.cs @@ -0,0 +1,9 @@ +using RefReturns; +using RefReturnsVersionTwo; +using ImplicitTypes; + +FirstExample.Tests(); +Console.WriteLine(); +SecondExample.Tests(); +Console.WriteLine(); +VarExample.ImplicitlyTyped(); diff --git a/docs/csharp/language-reference/statements/snippets/declarations/declarations.csproj b/docs/csharp/language-reference/statements/snippets/declarations/declarations.csproj new file mode 100644 index 0000000000000..240846380529c --- /dev/null +++ b/docs/csharp/language-reference/statements/snippets/declarations/declarations.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7 + preview + enable + + + diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs index 892d992095719..c6d315c332a3e 100644 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs +++ b/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs @@ -82,50 +82,4 @@ static void Main() } } // - - - class VarTest - { - #region compilation only - class Customer - { - public string City { get; set; } - public string Name { get; set; } - public string Phone { get; set; } - } - - #endregion - static void Main() - { - List customers = new List(); - // - // Example #1: var is optional when - // the select clause specifies a string - string[] words = { "apple", "strawberry", "grape", "peach", "banana" }; - var wordQuery = from word in words - where word[0] == 'g' - select word; - - // Because each element in the sequence is a string, - // not an anonymous type, var is optional here also. - foreach (string s in wordQuery) - { - Console.WriteLine(s); - } - - // Example #2: var is required because - // the select clause specifies an anonymous type - var custQuery = from cust in customers - where cust.City == "Phoenix" - select new { cust.Name, cust.Phone }; - - // var must be used because each item - // in the sequence is an anonymous type - foreach (var item in custQuery) - { - Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone); - } - // - } - } } diff --git a/samples/snippets/csharp/programming-guide/ref-returns/Program.cs b/samples/snippets/csharp/programming-guide/ref-returns/Program.cs deleted file mode 100644 index 71b743858000a..0000000000000 --- a/samples/snippets/csharp/programming-guide/ref-returns/Program.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace UseRefReturns -{ - using static System.Console; - using RefReturns; - using RefReturnsVersionTwo; - - public class Example - { - static void Main(string[] args) - { - FirstExample.Tests(); - WriteLine(); - SecondExample.Tests(); - } - } -} diff --git a/samples/snippets/csharp/programming-guide/ref-returns/ref-returns.csproj b/samples/snippets/csharp/programming-guide/ref-returns/ref-returns.csproj deleted file mode 100644 index 97a448acb36bc..0000000000000 --- a/samples/snippets/csharp/programming-guide/ref-returns/ref-returns.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - Exe - netcoreapp3.1 - 7.3 - RefReturns - - - From 6a729649400967e7e45e595e0fa328b934e3d6a3 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 14 Sep 2022 17:35:33 -0400 Subject: [PATCH 07/16] edits for ref readonly declarations Define value assignment and ref assignment. --- .../builtin-types/ref-struct.md | 2 +- .../csharp/language-reference/keywords/ref.md | 2 +- .../operators/assignment-operator.md | 24 +++++++----- .../statements/declarations.md | 39 ++++++++++++------- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 1a93d64519526..894a6c690a45f 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -18,7 +18,7 @@ Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a st Beginning with C# 8.0, you can define a disposable `ref` struct. To do that, ensure that a `ref` struct fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type. -Beginning with C# 11.0, a `ref struct` may contain `ref` fields. +Beginning with C# 11.0, a `ref struct` may contain `ref` fields. A `ref` field may be assigned or reassigned to refer to another object. Ref fields are declared using the same syntax as [`ref` local variables](../statements/declarations.md#ref-locals) Typically, you define a `ref` struct type when you need a type that also includes data members of `ref` struct types: diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index f4d8a18889b86..b7a2ec62b126c 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -124,7 +124,7 @@ In both examples the `ref` keyword must be used in both places, or the compiler Beginning with C# 7.3, the iteration variable of the `foreach` statement can be a ref local or ref readonly local variable. For more information, see the [foreach statement](../statements/iteration-statements.md#the-foreach-statement) article. -Also beginning with C# 7.3, you can reassign a ref local or ref readonly local variable with the [ref assignment operator](../operators/assignment-operator.md#ref-assignment-operator). +Also beginning with C# 7.3, you can reassign a ref local or ref readonly local variable with the [ref assignment operator](../operators/assignment-operator.md#ref-assignment). ## Ref readonly locals diff --git a/docs/csharp/language-reference/operators/assignment-operator.md b/docs/csharp/language-reference/operators/assignment-operator.md index a8fa30771c2da..368e5f9b7e41b 100644 --- a/docs/csharp/language-reference/operators/assignment-operator.md +++ b/docs/csharp/language-reference/operators/assignment-operator.md @@ -1,7 +1,7 @@ --- title: "Assignment operators - C# reference" description: "Learn about various C# assignment operators." -ms.date: 09/10/2019 +ms.date: 09/14/2022 f1_keywords: - "=_CSharpKeyword" helpviewer_keywords: @@ -10,7 +10,7 @@ ms.assetid: d802a6d5-32f0-42b8-b180-12f5a081bfc1 --- # Assignment operators (C# reference) -The assignment operator `=` assigns the value of its right-hand operand to a variable, a [property](../../programming-guide/classes-and-structs/properties.md), or an [indexer](../../programming-guide/indexers/index.md) element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-hand operand. The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. +The assignment operator `=` assigns the *value* of its right-hand operand to a variable, a [property](../../programming-guide/classes-and-structs/properties.md), or an [indexer](../../programming-guide/indexers/index.md) element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-hand operand. The type of the right-hand operand must be the same as the type of the left-hand operand or implicitly convertible to it. The assignment operator `=` is right-associative, that is, an expression of the form @@ -26,15 +26,21 @@ a = (b = c) The following example demonstrates the usage of the assignment operator with a local variable, a property, and an indexer element as its left-hand operand: -[!code-csharp-interactive[simple assignment](snippets/shared/AssignmentOperator.cs#Simple)] +:::code language="csharp" source="snippets/shared/AssignmentOperator.cs" id="SnippetSimple"::: -## ref assignment operator +The left operand of an assignment receives the *value* of the right had of the assignment. When the operands are [value types](../builtin-types/value-types.md), assignment copies the contents of the right hand operand. When the operands are [reference types](../builtin-types/reference-types.md), assignment copies the reference to the object. -Beginning with C# 7.3, you can use the ref assignment operator `= ref` to reassign a [ref local](../keywords/ref.md#ref-locals) or [ref readonly local](../keywords/ref.md#ref-readonly-locals) variable. The following example demonstrates the usage of the ref assignment operator: +This is called *value assignment*: the value is assigned. -[!code-csharp[ref assignment operator](snippets/shared/AssignmentOperator.cs#RefAssignment)] +## ref assignment -In the case of the ref assignment operator, both of its operands must be of the same type. +*Ref assignment* assigns the *reference* of its right hand operator to its left hand operand. The left operand is an alias to the right operand. The left operand must be a [ref local](../keywords/ref.md#ref-locals), [ref readonly local](../keywords/ref.md#ref-readonly-locals) or `ref` field in a [`ref struct`]../builtin-types/ref-struct.md). The following example demonstrates the usage of the ref assignment operator: + +:::code language="csharp" source="snippets/shared/AssignmentOperator.cs" id="SnippetRefAssignment"::: + +The `ref` must be applied to the right operands for a ref assignment. Both operands must be of the same type. + +This is called *ref assignment*: The variable now refers to a different object. ## Compound assignment @@ -60,9 +66,9 @@ Beginning with C# 8.0, you can use the null-coalescing assignment operator `??=` ## Operator overloadability -A user-defined type cannot [overload](operator-overloading.md) the assignment operator. However, a user-defined type can define an implicit conversion to another type. That way, the value of a user-defined type can be assigned to a variable, a property, or an indexer element of another type. For more information, see [User-defined conversion operators](user-defined-conversion-operators.md). +A user-defined type can't [overload](operator-overloading.md) the assignment operator. However, a user-defined type can define an implicit conversion to another type. That way, the value of a user-defined type can be assigned to a variable, a property, or an indexer element of another type. For more information, see [User-defined conversion operators](user-defined-conversion-operators.md). -A user-defined type cannot explicitly overload a compound assignment operator. However, if a user-defined type overloads a binary operator `op`, the `op=` operator, if it exists, is also implicitly overloaded. +A user-defined type can't explicitly overload a compound assignment operator. However, if a user-defined type overloads a binary operator `op`, the `op=` operator, if it exists, is also implicitly overloaded. ## C# language specification diff --git a/docs/csharp/language-reference/statements/declarations.md b/docs/csharp/language-reference/statements/declarations.md index 95d2b423917d2..f4ab508be1414 100644 --- a/docs/csharp/language-reference/statements/declarations.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -14,7 +14,7 @@ A *declaration statement* declares a new variable, and optionally, initializes i ## Implicitly typed local variables -Beginning with C# 3, variables that are declared at method scope can have an implicit "type" `var`. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of `i` are functionally equivalent: +Beginning with C# 3, variables that are declared at method scope can have an implicit "type" `var`. An implicitly typed local variable is strongly typed as if you had declared the type yourself, but the compiler determines the type. The following two declarations of `i` are functionally equivalent: ```csharp var i = 10; // Implicitly typed. @@ -39,13 +39,13 @@ List? ys = new(); In pattern matching, the `var` keyword is used in a [`var` pattern](../operators/patterns.md#var-pattern). -The following example shows two query expressions. In the first expression, the use of `var` is permitted but is not required, because the type of the query result can be stated explicitly as an `IEnumerable`. However, in the second expression, `var` allows the result to be a collection of anonymous types, and the name of that type is not accessible except to the compiler itself. Use of `var` eliminates the requirement to create a new class for the result. Note that in Example #2, the `foreach` iteration variable `item` must also be implicitly typed. +The following example shows two query expressions. In the first expression, the use of `var` is permitted but isn't required, because the type of the query result can be stated explicitly as an `IEnumerable`. However, in the second expression, `var` allows the result to be a collection of anonymous types, and the name of that type isn't accessible except to the compiler itself. Use of `var` eliminates the requirement to create a new class for the result. In Example #2, the `foreach` iteration variable `item` must also be implicitly typed. :::code language="csharp" source="./snippets/declarations/ImplicitlyTyped.cs" id="VarExample"::: ## Ref locals -Assume the `GetContactInformation` method is declared as a [ref return](jump-statements.md#ref-returns): +You add the `ref` keyword before the type of a variable to declare a `ref` local. Assume the `GetContactInformation` method is declared as a [ref return](jump-statements.md#ref-returns): ```csharp public ref Person GetContactInformation(string fname, string lname) @@ -57,9 +57,9 @@ A by-value assignment reads the value of a variable and assigns it to a new vari Person p = contacts.GetContactInformation("Brandie", "Best"); ``` -The preceding assignment declares `p` as a local variable. Its initial value is copied from reading the value returned by `GetContactInformation`. Any future assignments to `p` will not change the value of the variable returned by `GetContactInformation`. The variable `p` is no longer an alias to the variable returned. +The preceding assignment declares `p` as a local variable. Its initial value is copied from reading the value returned by `GetContactInformation`. Any future assignments to `p` won't change the value of the variable returned by `GetContactInformation`. The variable `p` is no longer an alias to the variable returned. -You declare a *ref local* variable to copy the alias to the original value. In the following assignment, `p` is an alias to the variable returned from `GetContactInformation`. +You declare a *ref* variable to copy the alias to the original value. In the following assignment, `p` is an alias to the variable returned from `GetContactInformation`. ```csharp ref Person p = ref contacts.GetContactInformation("Brandie", "Best"); @@ -67,24 +67,20 @@ ref Person p = ref contacts.GetContactInformation("Brandie", "Best"); Subsequent usage of `p` is the same as using the variable returned by `GetContactInformation` because `p` is an alias for that variable. Changes to `p` also change the variable returned from `GetContactInformation`. -The `ref` keyword is used both before the local variable declaration *and* before the method call. - You can access a value by reference in the same way. In some cases, accessing a value by reference increases performance by avoiding a potentially expensive copy operation. For example, the following statement shows how one can define a ref local value that is used to reference a value. ```csharp ref VeryLargeStruct reflocal = ref veryLargeStruct; ``` -The `ref` keyword is used both before the local variable declaration *and* before the value in the second example. Failure to include both `ref` keywords in the variable declaration and assignment in both examples results in compiler error CS8172, "Cannot initialize a by-reference variable with a value." - -Prior to C# 7.3, ref local variables couldn't be reassigned to refer to different storage after being initialized. That restriction has been removed. The following example shows a reassignment: +The `ref` keyword is used both before the local variable declaration *and* before the value in the second example. Failure to include both `ref` keywords in the variable declaration and assignment in both examples results in compiler error CS8172, "Can't initialize a by-reference variable with a value." ```csharp ref VeryLargeStruct reflocal = ref veryLargeStruct; // initialization refLocal = ref anotherVeryLargeStruct; // reassigned, refLocal refers to different storage. ``` - Ref local variables must still be initialized when they are declared. + Ref local variables must still be initialized when they're declared. The following example defines a `NumberStore` class that stores an array of integer values. The `FindNumber` method returns by reference the first number that is greater than or equal to the number passed as an argument. If no number is greater than or equal to the argument, the method returns the number in index 0. @@ -96,13 +92,26 @@ The following example calls the `NumberStore.FindNumber` method to retrieve the Without support for reference return values, such an operation is performed by returning the index of the array element along with its value. The caller can then use this index to modify the value in a separate method call. However, the caller can also modify the index to access and possibly modify other array values. -The following example shows how the `FindNumber` method could be rewritten after -C# 7.3 to use ref local reassignment: +The following example shows how the `FindNumber` method could be rewritten after C# 7.3 to use ref local reassignment: :::code language="csharp" source="./snippets/declarations/NumberStoreUpdated.cs" id="Snippet1"::: -This second version is more efficient with longer sequences in scenarios where the number sought is -closer to the end of the array, as the array is iterated from end towards the beginning, causing fewer items to be examined. +This second version is more efficient with longer sequences in scenarios where the number sought is closer to the end of the array, as the array is iterated from end towards the beginning, causing fewer items to be examined. + +### ref and readonly + +The `readonly` modifier can be applied to `ref` local variables and `ref` fields. The `readonly` modifier affects the expression to its right. See the following example declarations: + +```csharp +ref readonly int aConstant; // aConstant can't be value-reassigned. +readonly ref int Storage; // Storage can't be ref-reassigned. +readonly ref readonly int CantChange; // CantChange can't be value-reassigned or ref-reassigned. +``` + +- *value reassignment* means the value of the variable is reassigned. +- *ref assignment* means the variable now refers to a different object. + +The `readonly ref` and `readonly ref readonly` declarations are valid only on `ref` fields in a `ref struct`. ## See also From 81ef48a0c43062f9a212cb0a305e9d1984c79202 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 15 Sep 2022 11:39:56 -0400 Subject: [PATCH 08/16] add information on scoped. The scoped modifier limits the lifetime of the modified variable --- .../language-reference/builtin-types/ref-struct.md | 2 +- docs/csharp/language-reference/keywords/index.md | 3 ++- .../language-reference/statements/declarations.md | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 894a6c690a45f..3b43f1d97c1b0 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -18,7 +18,7 @@ Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a st Beginning with C# 8.0, you can define a disposable `ref` struct. To do that, ensure that a `ref` struct fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type. -Beginning with C# 11.0, a `ref struct` may contain `ref` fields. A `ref` field may be assigned or reassigned to refer to another object. Ref fields are declared using the same syntax as [`ref` local variables](../statements/declarations.md#ref-locals) +Beginning with C# 11.0, a `ref struct` may contain `ref` fields. A `ref` field may be assigned or reassigned to refer to another object. Ref fields are declared using the same syntax as [`ref` local variables](../statements/declarations.md#ref-locals). The compiler enforces scope rules on `ref` fields in `ref struct` types. The rules ensure that a reference doesn't outlive the object to which it refers. See the section on scoping rules in the article on [method parameters](../keywords/method-parameters.md#scope-of-references-and-values). Typically, you define a `ref` struct type when you need a type that also includes data members of `ref` struct types: diff --git a/docs/csharp/language-reference/keywords/index.md b/docs/csharp/language-reference/keywords/index.md index 22904c0669112..6fb418e112dad 100644 --- a/docs/csharp/language-reference/keywords/index.md +++ b/docs/csharp/language-reference/keywords/index.md @@ -149,9 +149,10 @@ A contextual keyword is used to provide a specific meaning in the code, but it i [`record`](../../fundamentals/types/records.md) [`remove`](remove.md) [`required`](required.md) - [`select`](select-clause.md) + [`scoped`](../statements/declarations.md#scoped-ref) :::column-end::: :::column::: + [`select`](select-clause.md) [`set`](set.md) [`unmanaged` (function pointer calling convention)](../unsafe-code.md#function-pointers) [`unmanaged` (generic type constraint)](../../programming-guide/generics/constraints-on-type-parameters.md#unmanaged-constraint) diff --git a/docs/csharp/language-reference/statements/declarations.md b/docs/csharp/language-reference/statements/declarations.md index f4ab508be1414..9b5969abc1090 100644 --- a/docs/csharp/language-reference/statements/declarations.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -98,6 +98,8 @@ The following example shows how the `FindNumber` method could be rewritten after This second version is more efficient with longer sequences in scenarios where the number sought is closer to the end of the array, as the array is iterated from end towards the beginning, causing fewer items to be examined. +The compiler enforces scope rules on `ref` variables: `ref` locals, `ref` parameters, and `ref` fields in `ref struct` types. The rules ensure that a reference doesn't outlive the object to which it refers. See the section on scoping rules in the article on [method parameters](../keywords/method-parameters.md#scope-of-references-and-values). + ### ref and readonly The `readonly` modifier can be applied to `ref` local variables and `ref` fields. The `readonly` modifier affects the expression to its right. See the following example declarations: @@ -113,6 +115,14 @@ readonly ref readonly int CantChange; // CantChange can't be value-reassigned or The `readonly ref` and `readonly ref readonly` declarations are valid only on `ref` fields in a `ref struct`. +## scoped ref + +The contextual keyword `scoped` restricts the lifetime of a value. The `scoped` modifier restricts the [*ref-safe-to-escape* or *safe-to-escape* lifetime](../keywords/method-parameters.md#scope-of-references-and-value), respectively, to the current method. Effectively, adding the `scoped` modifier asserts that your code won't extend the lifetime of the variable. + +You can apply `scaped` to a parameter or local variable. The `scoped` modifier may be applied to parameters and locals when the type is a [`ref struct`](../builtin-types/ref-struct.md). Otherwise, the `scoped` modifier may be applied only to local variables that are [ref types](#ref-locals). That includes local variables declared with the `ref` modifier and parameters declared with the `in`, `ref` or `out` modifiers. + +The `scoped` modifier is implicitly added to `this` in methods declared in a `struct`, `out` parameters, and `ref` parameters when the type is a `ref struct`. + ## See also - [ref keyword](../keywords/ref.md) From 5ba43d06e21751103f0a222075d4ab01484fe001 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 15 Sep 2022 14:23:18 -0400 Subject: [PATCH 09/16] edit ref index article. --- .../language-reference/keywords/index.md | 8 +-- .../csharp/language-reference/keywords/ref.md | 69 ++++++++++++------- .../snippets}/RefParameterModifier.cs | 0 3 files changed, 47 insertions(+), 30 deletions(-) rename {samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier => docs/csharp/language-reference/keywords/snippets}/RefParameterModifier.cs (100%) diff --git a/docs/csharp/language-reference/keywords/index.md b/docs/csharp/language-reference/keywords/index.md index 6fb418e112dad..2ecfe86713749 100644 --- a/docs/csharp/language-reference/keywords/index.md +++ b/docs/csharp/language-reference/keywords/index.md @@ -1,7 +1,7 @@ --- description: "C# Keywords" title: "C# Keywords" -ms.date: 12/15/2021 +ms.date: 09/15/2022 f1_keywords: - "cs.keywords" helpviewer_keywords: @@ -13,9 +13,9 @@ ms.custom: "updateeachrelease" --- # C# Keywords -Keywords are predefined, reserved identifiers that have special meanings to the compiler. They cannot be used as identifiers in your program unless they include `@` as a prefix. For example, `@if` is a valid identifier, but `if` is not because `if` is a keyword. +Keywords are predefined, reserved identifiers that have special meanings to the compiler. They can't be used as identifiers in your program unless they include `@` as a prefix. For example, `@if` is a valid identifier, but `if` isn't because `if` is a keyword. -The first table in this topic lists keywords that are reserved identifiers in any part of a C# program. The second table in this topic lists the contextual keywords in C#. Contextual keywords have special meaning only in a limited program context and can be used as identifiers outside that context. Generally, as new keywords are added to the C# language, they are added as contextual keywords in order to avoid breaking programs written in earlier versions. +The first table in this article lists keywords that are reserved identifiers in any part of a C# program. The second table in this article lists the contextual keywords in C#. Contextual keywords have special meaning only in a limited program context and can be used as identifiers outside that context. Generally, as new keywords are added to the C# language, they're added as contextual keywords in order to avoid breaking programs written in earlier versions. :::row::: :::column::: @@ -108,7 +108,7 @@ The first table in this topic lists keywords that are reserved identifiers in an ## Contextual keywords -A contextual keyword is used to provide a specific meaning in the code, but it is not a reserved word in C#. Some contextual keywords, such as `partial` and `where`, have special meanings in two or more contexts. +A contextual keyword is used to provide a specific meaning in the code, but it isn't a reserved word in C#. Some contextual keywords, such as `partial` and `where`, have special meanings in two or more contexts. :::row::: :::column::: diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index b7a2ec62b126c..f021007e2b881 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -10,12 +10,13 @@ helpviewer_keywords: --- # ref (C# Reference) -The `ref` keyword indicates that a value is passed by reference. It is used in four different contexts: +The `ref` keyword indicates that a variable is a reference, or an alias for another object. It's used in five different contexts: - In a method signature and in a method call, to pass an argument to a method by reference. For more information, see [Passing an argument by reference](#passing-an-argument-by-reference). - In a method signature, to return a value to the caller by reference. For more information, see [Reference return values](#reference-return-values). - In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify. Or to indicate that a local variable accesses another value by reference. For more information, see [Ref locals](#ref-locals). -- In a `struct` declaration, to declare a `ref struct` or a `readonly ref struct`. For more information, see the [`ref` struct](../builtin-types/ref-struct.md) section of the [Structure types](../builtin-types/struct.md) article. +- In a `struct` declaration, to declare a `ref struct` or a `readonly ref struct`. For more information, see the [`ref` struct](../builtin-types/ref-struct.md) article. +- In a `ref struct` declaration, to declare that a field is a reference. See the [`ref` field](../builtin-types/ref-struct.md) article. ## Passing an argument by reference @@ -24,15 +25,15 @@ When used in a method's parameter list, the `ref` keyword indicates that an argu For example, suppose the caller passes a local variable expression or an array element access expression. The called method can then replace the object to which the ref parameter refers. In that case, the caller's local variable or the array element refers to the new object when the method returns. > [!NOTE] -> Don't confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by `ref` regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference. +> Don't confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by `ref` regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference. To use a `ref` parameter, both the method definition and the calling method must explicitly use the `ref` keyword, as shown in the following example. (Except that the calling method can omit `ref` when making a COM call.) -[!code-csharp-interactive[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#1)] +:::code language="csharp" source="snippets/RefParameterModifier.cs" id="Snippet1"::: -An argument that is passed to a `ref` or `in` parameter must be initialized before it is passed. This requirement differs from [out](out-parameter-modifier.md) parameters, whose arguments don't have to be explicitly initialized before they are passed. +An argument that is passed to a `ref` or `in` parameter must be initialized before it's passed. This requirement differs from [out](out-parameter-modifier.md) parameters, whose arguments don't have to be explicitly initialized before they're passed. -Members of a class can't have signatures that differ only by `ref`, `in`, or `out`. A compiler error occurs if the only difference between two members of a type is that one of them has a `ref` parameter and the other has an `out`, or `in` parameter. The following code, for example, doesn't compile. +Members of a class can't have signatures that differ only by `ref`, `in`, or `out`. A compiler error occurs if the only difference between two members of a type is that one of them has a `ref` parameter and the other has an `out`, or `in` parameter. The following code, for example, doesn't compile. ```csharp class CS0663_Example @@ -45,29 +46,29 @@ class CS0663_Example ``` However, methods can be overloaded when one method has a `ref`, `in`, or `out` parameter and the other has a parameter that is passed by value, as shown in the following example. - -[!code-csharp[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#2)] - - In other situations that require signature matching, such as hiding or overriding, `in`, `ref`, and `out` are part of the signature and don't match each other. - - Properties are not variables. They're methods, and cannot be passed to `ref` parameters. - - You can't use the `ref`, `in`, and `out` keywords for the following kinds of methods: - -- Async methods, which you define by using the [async](async.md) modifier. + +:::code language="csharp" source="snippets/RefParameterModifier.cs" id="Snippet2"::: + +In other situations that require signature matching, such as hiding or overriding, `in`, `ref`, and `out` are part of the signature and don't match each other. + +Properties aren't variables. They're methods, and can't be passed to `ref` parameters. + +You can't use the `ref`, `in`, and `out` keywords for the following kinds of methods: + +- Async methods, which you define by using the [async](async.md) modifier. - Iterator methods, which include a [yield return](yield.md) or `yield break` statement. [extension methods](../../programming-guide/classes-and-structs/extension-methods.md) also have restrictions on the use of these keywords: -- The `out` keyword cannot be used on the first argument of an extension method. -- The `ref` keyword cannot be used on the first argument of an extension method when the argument is not a struct, or a generic type not constrained to be a struct. -- The `in` keyword cannot be used unless the first argument is a struct. The `in` keyword cannot be used on any generic type, even when constrained to be a struct. +- The `out` keyword can't be used on the first argument of an extension method. +- The `ref` keyword can't be used on the first argument of an extension method when the argument isn't a struct, or a generic type not constrained to be a struct. +- The `in` keyword can't be used unless the first argument is a struct. The `in` keyword can't be used on any generic type, even when constrained to be a struct. ## Passing an argument by reference: An example The previous examples pass value types by reference. You can also use the `ref` keyword to pass reference types by reference. Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller. The storage location of the object is passed to the method as the value of the reference parameter. If you change the value in the storage location of the parameter (to point to a new object), you also change the storage location to which the caller refers. The following example passes an instance of a reference type as a `ref` parameter. - -[!code-csharp[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#3)] + +:::code language="csharp" source="snippets/RefParameterModifier.cs" id="Snippet3"::: For more information about how to pass reference types by value and by reference, see [Passing Reference-Type Parameters](method-parameters.md). @@ -101,7 +102,7 @@ For an example, see [A ref returns and ref locals example](#a-ref-returns-and-re ## Ref locals -A ref local variable is used to refer to values returned using `return ref`. A ref local variable cannot be initialized to a non-ref return value. In other words, the right-hand side of the initialization must be a reference. Any modifications to the value of the ref local are reflected in the state of the object whose method returned the value by reference. +A ref local variable is used to refer to values returned using `return ref`. A ref local variable can't be initialized to a non-ref return value. In other words, the right-hand side of the initialization must be a reference. Any modifications to the value of the ref local are reflected in the state of the object whose method returned the value by reference. You define a ref local by using the `ref` keyword in two places: @@ -120,7 +121,7 @@ You can access a value by reference in the same way. In some cases, accessing a ref VeryLargeStruct reflocal = ref veryLargeStruct; ``` -In both examples the `ref` keyword must be used in both places, or the compiler generates error CS8172, "Cannot initialize a by-reference variable with a value." +In both examples the `ref` keyword must be used in both places, or the compiler generates error CS8172, "Can't initialize a by-reference variable with a value." Beginning with C# 7.3, the iteration variable of the `foreach` statement can be a ref local or ref readonly local variable. For more information, see the [foreach statement](../statements/iteration-statements.md#the-foreach-statement) article. @@ -128,17 +129,33 @@ Also beginning with C# 7.3, you can reassign a ref local or ref readonly local v ## Ref readonly locals -A ref readonly local is used to refer to values returned by a method or property that has `ref readonly` in its signature and uses `return ref`. A `ref readonly` variable combines the properties of a `ref` local variable with a `readonly` variable: it's an alias to the storage it's assigned to, and it cannot be modified. +A ref readonly local is used to refer to values returned by a method or property that has `ref readonly` in its signature and uses `return ref`. A `ref readonly` variable combines the properties of a `ref` local variable with a `readonly` variable: it's an alias to the storage it's assigned to, and it can't be modified. ## A ref returns and ref locals example The following example defines a `Book` class that has two fields, `Title` and `Author`. It also defines a `BookCollection` class that includes a private array of `Book` objects. Individual book objects are returned by reference by calling its `GetBookByTitle` method. -[!code-csharp[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#4)] +:::code language="csharp" source="snippets/RefParameterModifier.cs" id="Snippet4"::: When the caller stores the value returned by the `GetBookByTitle` method as a ref local, changes that the caller makes to the return value are reflected in the `BookCollection` object, as the following example shows. -[!code-csharp[csrefKeywordsMethodParams#6](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#5)] +:::code language="csharp" source="snippets/RefParameterModifier.cs" id="Snippet5"::: + +## ref fields + +In [`ref struct`](../builtin-types/ref-struct.md) types, you can declare fields that are `ref` fields. `ref` fields are valid only in `ref struct` types to ensure the reference doesn't outlive the object it refers to. This feature enables types like : + +```csharp +public readonly ref struct Span +{ + internal readonly ref T _reference; + private readonly int _length; + + // etc +} +``` + +The `Span` type stores a reference through which it accesses the consecutive elements. A reference enables the `Span` object to avoid making copies of the storage it refers to. ## C# language specification diff --git a/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs b/docs/csharp/language-reference/keywords/snippets/RefParameterModifier.cs similarity index 100% rename from samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs rename to docs/csharp/language-reference/keywords/snippets/RefParameterModifier.cs From e524329cc410ee9361885108240470e13b7115dd Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 15 Sep 2022 14:41:40 -0400 Subject: [PATCH 10/16] final edits. --- docs/csharp/language-reference/builtin-types/ref-struct.md | 2 +- docs/csharp/language-reference/builtin-types/struct.md | 2 +- docs/csharp/language-reference/keywords/method-parameters.md | 2 +- docs/csharp/language-reference/keywords/ref.md | 2 +- docs/csharp/language-reference/statements/declarations.md | 2 +- docs/csharp/language-reference/statements/jump-statements.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 3b43f1d97c1b0..9b7ff5e4993c1 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -1,7 +1,7 @@ --- title: "Ref Struct types - C# reference" description: Learn about the ref struct type in C# -ms.date: 09/02/2022 +ms.date: 09/15/2022 --- # `ref` Structure types (C# reference) diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index 79827ab7a4f38..2f997f71d7776 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -1,7 +1,7 @@ --- title: "Structure types - C# reference" description: Learn about the struct type in C# -ms.date: 09/02/2022 +ms.date: 09/15/2022 f1_keywords: - "struct_CSharpKeyword" helpviewer_keywords: diff --git a/docs/csharp/language-reference/keywords/method-parameters.md b/docs/csharp/language-reference/keywords/method-parameters.md index 6455a780f4dcc..cb5180de30a3a 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -1,7 +1,7 @@ --- description: "Method Parameters - C# Reference" title: "Method Parameters - C# Reference" -ms.date: 09/01/2022 +ms.date: 09/15/2022 helpviewer_keywords: - "methods [C#], parameters" - "method parameters [C#]" diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index f021007e2b881..2e19818a149b6 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -1,7 +1,7 @@ --- description: "ref keyword - C# Reference" title: "ref keyword - C# Reference" -ms.date: 03/29/2021 +ms.date: 09/15/202 f1_keywords: - "ref_CSharpKeyword" helpviewer_keywords: diff --git a/docs/csharp/language-reference/statements/declarations.md b/docs/csharp/language-reference/statements/declarations.md index 9b5969abc1090..fabb0c1dba033 100644 --- a/docs/csharp/language-reference/statements/declarations.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -1,7 +1,7 @@ --- title: "Declaration statements - C# reference" description: "Declaration statements, including `var`, `ref` locals, and `ref` fields - C# reference" -ms.date: 09/08/2022 +ms.date: 09/15/2022 f1_keywords: - "var" - "var_CSharpKeyword" diff --git a/docs/csharp/language-reference/statements/jump-statements.md b/docs/csharp/language-reference/statements/jump-statements.md index 1dd8a27cdc05c..87ca44e2077b7 100644 --- a/docs/csharp/language-reference/statements/jump-statements.md +++ b/docs/csharp/language-reference/statements/jump-statements.md @@ -1,7 +1,7 @@ --- title: "Jump statements - C# reference" description: "Learn about C# jump statements: break, continue, return, and goto." -ms.date: 09/08/2022 +ms.date: 09/15/2022 f1_keywords: - "break_CSharpKeyword" - "continue_CSharpKeyword" From 1b470096d21f88a98323683b84babc42ab5af2a4 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 15 Sep 2022 15:08:51 -0400 Subject: [PATCH 11/16] update the What's new article. --- .openpublishing.redirection.csharp.json | 2 +- docs/csharp/whats-new/csharp-11.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 1f764e0114a7b..1e3c059b4da15 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -115,7 +115,7 @@ }, { "source_path_from_root": "/docs/csharp/getting-started/whats-new.md", - "redirect_url": "/dotnet/csharp/whats-new/csharp-10" + "redirect_url": "/dotnet/csharp/whats-new/csharp-11" }, { "source_path_from_root": "/docs/csharp/getting-started/with-visual-studio-2017.md", diff --git a/docs/csharp/whats-new/csharp-11.md b/docs/csharp/whats-new/csharp-11.md index 46bc8740daa68..bd4c4a7120171 100644 --- a/docs/csharp/whats-new/csharp-11.md +++ b/docs/csharp/whats-new/csharp-11.md @@ -21,6 +21,7 @@ The following features are available in Visual Studio 2022 version 17.3: - [Numeric IntPtr](#numeric-intptr-and-uintptr) - [UTF-8 string literals](#utf-8-string-literals) - [Required members](#required-members) +- [`ref` fields and `scoped ref`](#ref-fields-and-ref-scoped-variables) The following features are available in Visual Studio 2022 version 17.2: @@ -187,6 +188,12 @@ You can add the [`required` modifier](../language-reference/keywords/required.md For more information on required members, See the [init-only](../properties.md#init-only) section of the properties article. +## `ref` fields and `ref scoped` variables + +You can declare `ref` fields inside a [`ref struct`](../language-reference/builtin-types/ref-struct.md). This supports types such as without special attributes or hidden internal types. + +You can add the [`scoped`](../language-reference/statements/declarations.md#scoped-ref) modifier to any `ref` declaration. This limits the [scope](../language-reference/keywords/method-parameters.md#scope-of-references-and-values) where the reference can escape to. + ## File scoped types Beginning in C# 11, you can use the `file` access modifier to create a type whose visibility is scoped to the source file in which it is declared. This feature helps source generator authors avoid naming collisions. You can learn more about this feature in the article on [file-scoped types](../language-reference/keywords/file.md) in the language reference. From 117e20085e93c9be2a2ca92f26cf895625ce9747 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 15 Sep 2022 15:14:13 -0400 Subject: [PATCH 12/16] build warnings. --- docs/csharp/language-reference/keywords/ref.md | 4 ++-- docs/csharp/language-reference/statements/declarations.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index 2e19818a149b6..bc771a534fbb6 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -1,7 +1,7 @@ --- description: "ref keyword - C# Reference" title: "ref keyword - C# Reference" -ms.date: 09/15/202 +ms.date: 09/15/2022 f1_keywords: - "ref_CSharpKeyword" helpviewer_keywords: @@ -94,7 +94,7 @@ In order for the caller to modify the object's state, the reference return value Here's a more complete ref return example, showing both the method signature and method body. -[!code-csharp[FindReturningRef](~/samples/snippets/csharp/language-reference/keywords/in-ref-out-modifier/RefParameterModifier.cs#FindReturningRef)] +:::code language="csharp" source="snippets/RefParameterModifier.cs" id="SnippetFindReturningRef"::: The called method may also declare the return value as `ref readonly` to return the value by reference, and enforce that the calling code can't modify the returned value. The calling method can avoid copying the returned value by storing the value in a local [ref readonly](#ref-readonly-locals) variable. diff --git a/docs/csharp/language-reference/statements/declarations.md b/docs/csharp/language-reference/statements/declarations.md index fabb0c1dba033..0a5d4808bb840 100644 --- a/docs/csharp/language-reference/statements/declarations.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -117,7 +117,7 @@ The `readonly ref` and `readonly ref readonly` declarations are valid only on `r ## scoped ref -The contextual keyword `scoped` restricts the lifetime of a value. The `scoped` modifier restricts the [*ref-safe-to-escape* or *safe-to-escape* lifetime](../keywords/method-parameters.md#scope-of-references-and-value), respectively, to the current method. Effectively, adding the `scoped` modifier asserts that your code won't extend the lifetime of the variable. +The contextual keyword `scoped` restricts the lifetime of a value. The `scoped` modifier restricts the [*ref-safe-to-escape* or *safe-to-escape* lifetime](../keywords/method-parameters.md#scope-of-references-and-values), respectively, to the current method. Effectively, adding the `scoped` modifier asserts that your code won't extend the lifetime of the variable. You can apply `scaped` to a parameter or local variable. The `scoped` modifier may be applied to parameters and locals when the type is a [`ref struct`](../builtin-types/ref-struct.md). Otherwise, the `scoped` modifier may be applied only to local variables that are [ref types](#ref-locals). That includes local variables declared with the `ref` modifier and parameters declared with the `in`, `ref` or `out` modifiers. From adbcdb283936017b7eed71952b8ea464332bf264 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 16 Sep 2022 15:58:50 -0400 Subject: [PATCH 13/16] Apply suggestions from code review Co-authored-by: David Pine --- .../builtin-types/ref-struct.md | 20 +++++++++---------- .../builtin-types/struct.md | 2 +- .../keywords/method-parameters.md | 4 ++-- .../csharp/language-reference/keywords/ref.md | 2 +- .../keywords/snippets/ParameterModifiers.cs | 3 ++- .../keywords/snippets/PassParameters.cs | 2 +- .../operators/assignment-operator.md | 2 +- .../statements/declarations.md | 8 ++++---- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 9b7ff5e4993c1..f03823afa9b88 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -7,20 +7,20 @@ ms.date: 09/15/2022 Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a structure type. Instances of a `ref` struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref` struct types as follows: -- A `ref` struct can't be the element type of an array. -- A `ref` struct can't be a declared type of a field of a class or a non-`ref` struct. -- A `ref` struct can't implement interfaces. -- A `ref` struct can't be boxed to or . -- A `ref` struct can't be a type argument. -- A `ref` struct variable can't be captured by a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md). -- A `ref` struct variable can't be used in an [`async`](../keywords/async.md) method. However, you can use `ref` struct variables in synchronous methods, for example, in methods that return or . -- A `ref` struct variable can't be used in [iterators](../../iterators.md). +- A `ref struct` can't be the element type of an array. +- A `ref struct` can't be a declared type of a field of a class or a non-`ref` struct. +- A `ref struct` can't implement interfaces. +- A `ref struct` can't be boxed to or . +- A `ref struct` can't be a type argument. +- A `ref struct` variable can't be captured by a [lambda expression](../operators/lambda-expressions.md) or a [local function](../../programming-guide/classes-and-structs/local-functions.md). +- A `ref struct` variable can't be used in an [`async`](../keywords/async.md) method. However, you can use `ref struct` variables in synchronous methods, for example, in methods that return or . +- A `ref struct` variable can't be used in [iterators](../../iterators.md). -Beginning with C# 8.0, you can define a disposable `ref` struct. To do that, ensure that a `ref` struct fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type. +Beginning with C# 8.0, you can define a disposable `ref struct`. To do that, ensure that a `ref struct` fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance or extension `Dispose` method, which is accessible, parameterless and has a `void` return type. Beginning with C# 11.0, a `ref struct` may contain `ref` fields. A `ref` field may be assigned or reassigned to refer to another object. Ref fields are declared using the same syntax as [`ref` local variables](../statements/declarations.md#ref-locals). The compiler enforces scope rules on `ref` fields in `ref struct` types. The rules ensure that a reference doesn't outlive the object to which it refers. See the section on scoping rules in the article on [method parameters](../keywords/method-parameters.md#scope-of-references-and-values). -Typically, you define a `ref` struct type when you need a type that also includes data members of `ref` struct types: +Typically, you define a `ref` struct type when you need a type that also includes data members of `ref struct` types: :::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetRefStruct"::: diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index 2f997f71d7776..d67b70c3a0711 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -16,7 +16,7 @@ A *structure type* (or *struct type*) is a [value type](value-types.md) that can [!code-csharp[struct example](snippets/shared/StructType.cs#StructExample)] -`ref struct` types and `readonly ref struct` types are covered in the article on [`ref struct` types](ref-struct.md). +`ref struct` types and `readonly ref struct` types are covered in the article on [ref struct types](ref-struct.md). Structure types have *value semantics*. That is, a variable of a structure type contains an instance of the type. By default, variable values are copied on assignment, passing an argument to a method, and returning a method result. For structure-type variables, an instance of the type is copied. For more information, see [Value types](value-types.md). diff --git a/docs/csharp/language-reference/keywords/method-parameters.md b/docs/csharp/language-reference/keywords/method-parameters.md index cb5180de30a3a..aefcc667204a4 100644 --- a/docs/csharp/language-reference/keywords/method-parameters.md +++ b/docs/csharp/language-reference/keywords/method-parameters.md @@ -15,7 +15,7 @@ In C#, arguments can be passed to parameters either by value or by reference. Re - *Pass by value* means **passing a copy of the variable** to the method. - *Pass by reference* means **passing access to the variable** to the method. - A variable of a *reference type* contains a reference to its data. -- A variable of a *structure type* contains its data directly. +- A variable of a *value type* contains its data directly. Because a struct is a [value type](../builtin-types/value-types.md), when you [pass a struct by value](#pass-a-value-type-by-value) to a method, the method receives and operates on a copy of the struct argument. The method has no access to the original struct in the calling method and therefore can't change it in any way. The method can change only the copy. @@ -42,7 +42,7 @@ The variable `n` is a value type. It contains its data, the value `5`. When `Squ ## Pass a value type by reference -When you pass a *value* type *by by reference*: +When you pass a *value* type *by reference*: - If the method assigns the parameter to refer to a different object, those changes **aren't** visible from the caller. - If the method modifies the state of the object referred to by the parameter, those changes **aren't** visible from the caller. diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index bc771a534fbb6..5592fc06837e6 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -151,7 +151,7 @@ public readonly ref struct Span internal readonly ref T _reference; private readonly int _length; - // etc + // Omitted for brevity... } ``` diff --git a/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs b/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs index 1499fa42d2287..99cc929369370 100644 --- a/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs +++ b/docs/csharp/language-reference/keywords/snippets/ParameterModifiers.cs @@ -4,7 +4,8 @@ using System.Text; using System.Threading.Tasks; -namespace keywords; +namespace Keywords; + internal class ParameterModifiers { internal static void PassValueByValue() diff --git a/docs/csharp/language-reference/keywords/snippets/PassParameters.cs b/docs/csharp/language-reference/keywords/snippets/PassParameters.cs index 659043c74476c..7bd61b70ba5be 100644 --- a/docs/csharp/language-reference/keywords/snippets/PassParameters.cs +++ b/docs/csharp/language-reference/keywords/snippets/PassParameters.cs @@ -1,6 +1,6 @@ using System; -namespace keywords; +namespace Keywords; // class TheClass diff --git a/docs/csharp/language-reference/operators/assignment-operator.md b/docs/csharp/language-reference/operators/assignment-operator.md index 368e5f9b7e41b..bceb9f1569aa8 100644 --- a/docs/csharp/language-reference/operators/assignment-operator.md +++ b/docs/csharp/language-reference/operators/assignment-operator.md @@ -28,7 +28,7 @@ The following example demonstrates the usage of the assignment operator with a l :::code language="csharp" source="snippets/shared/AssignmentOperator.cs" id="SnippetSimple"::: -The left operand of an assignment receives the *value* of the right had of the assignment. When the operands are [value types](../builtin-types/value-types.md), assignment copies the contents of the right hand operand. When the operands are [reference types](../builtin-types/reference-types.md), assignment copies the reference to the object. +The left operand of an assignment receives the *value* of the right hand of the assignment. When the operands are [value types](../builtin-types/value-types.md), the assignment copies the contents of the right-hand operand. When the operands are [reference types](../builtin-types/reference-types.md), assignment copies the reference to the object. This is called *value assignment*: the value is assigned. diff --git a/docs/csharp/language-reference/statements/declarations.md b/docs/csharp/language-reference/statements/declarations.md index 0a5d4808bb840..3462f1925eed6 100644 --- a/docs/csharp/language-reference/statements/declarations.md +++ b/docs/csharp/language-reference/statements/declarations.md @@ -14,11 +14,11 @@ A *declaration statement* declares a new variable, and optionally, initializes i ## Implicitly typed local variables -Beginning with C# 3, variables that are declared at method scope can have an implicit "type" `var`. An implicitly typed local variable is strongly typed as if you had declared the type yourself, but the compiler determines the type. The following two declarations of `i` are functionally equivalent: +Beginning with C# 3, variables that are declared at method scope can have an implicit "type" `var`. An implicitly typed local variable is strongly typed as if you had declared the type yourself, but the compiler determines the type. The following two declarations of `a` and `b` are functionally equivalent: ```csharp -var i = 10; // Implicitly typed. -int i = 10; // Explicitly typed. +var a = 10; // Implicitly typed. +int b = 10; // Explicitly typed. ``` > [!IMPORTANT] @@ -80,7 +80,7 @@ ref VeryLargeStruct reflocal = ref veryLargeStruct; // initialization refLocal = ref anotherVeryLargeStruct; // reassigned, refLocal refers to different storage. ``` - Ref local variables must still be initialized when they're declared. +Ref local variables must still be initialized when they're declared. The following example defines a `NumberStore` class that stores an array of integer values. The `FindNumber` method returns by reference the first number that is greater than or equal to the number passed as an argument. If no number is greater than or equal to the argument, the method returns the number in index 0. From 280449a2b83262f52c30e1a64fea0c78865a791e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 16 Sep 2022 15:59:12 -0400 Subject: [PATCH 14/16] Update docs/csharp/language-reference/builtin-types/ref-struct.md Co-authored-by: David Pine --- docs/csharp/language-reference/builtin-types/ref-struct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index f03823afa9b88..2b917dfac2ebd 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -5,7 +5,7 @@ ms.date: 09/15/2022 --- # `ref` Structure types (C# reference) -Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a structure type. Instances of a `ref` struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref` struct types as follows: +Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a value type. Instances of a `ref` struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref` struct types as follows: - A `ref struct` can't be the element type of an array. - A `ref struct` can't be a declared type of a field of a class or a non-`ref` struct. From 024fa2dcf45e4c49b28d322a7a38bcb87df6afc7 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 16 Sep 2022 16:03:21 -0400 Subject: [PATCH 15/16] code fence `ref struct` --- .../language-reference/builtin-types/ref-struct.md | 10 +++++----- docs/csharp/language-reference/builtin-types/struct.md | 4 ++-- docs/csharp/language-reference/keywords/ref.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 2b917dfac2ebd..8be21d0b06b6d 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -5,10 +5,10 @@ ms.date: 09/15/2022 --- # `ref` Structure types (C# reference) -Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a value type. Instances of a `ref` struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref` struct types as follows: +Beginning with C# 7.2, you can use the `ref` modifier in the declaration of a value type. Instances of a `ref struct` type are allocated on the stack and can't escape to the managed heap. To ensure that, the compiler limits the usage of `ref struct` types as follows: - A `ref struct` can't be the element type of an array. -- A `ref struct` can't be a declared type of a field of a class or a non-`ref` struct. +- A `ref struct` can't be a declared type of a field of a class or a non-`ref struct`. - A `ref struct` can't implement interfaces. - A `ref struct` can't be boxed to or . - A `ref struct` can't be a type argument. @@ -20,15 +20,15 @@ Beginning with C# 8.0, you can define a disposable `ref struct`. To do that, ens Beginning with C# 11.0, a `ref struct` may contain `ref` fields. A `ref` field may be assigned or reassigned to refer to another object. Ref fields are declared using the same syntax as [`ref` local variables](../statements/declarations.md#ref-locals). The compiler enforces scope rules on `ref` fields in `ref struct` types. The rules ensure that a reference doesn't outlive the object to which it refers. See the section on scoping rules in the article on [method parameters](../keywords/method-parameters.md#scope-of-references-and-values). -Typically, you define a `ref` struct type when you need a type that also includes data members of `ref struct` types: +Typically, you define a `ref struct` type when you need a type that also includes data members of `ref struct` types: :::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetRefStruct"::: -To declare a `ref` struct as `readonly`, combine the `readonly` and `ref` modifiers in the type declaration (the `readonly` modifier must come before the `ref` modifier): +To declare a `ref struct` as `readonly`, combine the `readonly` and `ref` modifiers in the type declaration (the `readonly` modifier must come before the `ref` modifier): :::code language="csharp" source="snippets/shared/StructType.cs" id="SnippetReadonlyRef"::: -In .NET, examples of a `ref` struct are and . +In .NET, examples of a `ref struct` are and . ## C# language specification diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index d67b70c3a0711..fb4305d5975d6 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -81,7 +81,7 @@ Beginning with C# 10, you can use the [`with` expression](../operators/with-expr ## `record` struct -Beginning with C# 10, you can define record structure types. Record types provide built-in functionality for encapsulating data. You can define both `record struct` and `readonly record struct` types. A record struct can't be a [`ref` struct](ref-struct.md). For more information and examples, see [Records](record.md). +Beginning with C# 10, you can define record structure types. Record types provide built-in functionality for encapsulating data. You can define both `record struct` and `readonly record struct` types. A record struct can't be a [`ref struct`](ref-struct.md). For more information and examples, see [Records](record.md). ## Struct initialization and default values @@ -135,7 +135,7 @@ You also use the `struct` keyword in the [`struct` constraint](../../programming ## Conversions -For any structure type (except [`ref` struct](ref-struct.md) types), there exist [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the and types. There exist also boxing and unboxing conversions between a structure type and any interface that it implements. +For any structure type (except [`ref struct`](ref-struct.md) types), there exist [boxing and unboxing](../../programming-guide/types/boxing-and-unboxing.md) conversions to and from the and types. There exist also boxing and unboxing conversions between a structure type and any interface that it implements. ## C# language specification diff --git a/docs/csharp/language-reference/keywords/ref.md b/docs/csharp/language-reference/keywords/ref.md index 5592fc06837e6..8125dc4b986ef 100644 --- a/docs/csharp/language-reference/keywords/ref.md +++ b/docs/csharp/language-reference/keywords/ref.md @@ -15,7 +15,7 @@ The `ref` keyword indicates that a variable is a reference, or an alias for anot - In a method signature and in a method call, to pass an argument to a method by reference. For more information, see [Passing an argument by reference](#passing-an-argument-by-reference). - In a method signature, to return a value to the caller by reference. For more information, see [Reference return values](#reference-return-values). - In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify. Or to indicate that a local variable accesses another value by reference. For more information, see [Ref locals](#ref-locals). -- In a `struct` declaration, to declare a `ref struct` or a `readonly ref struct`. For more information, see the [`ref` struct](../builtin-types/ref-struct.md) article. +- In a `struct` declaration, to declare a `ref struct` or a `readonly ref struct`. For more information, see the [`ref struct`](../builtin-types/ref-struct.md) article. - In a `ref struct` declaration, to declare that a field is a reference. See the [`ref` field](../builtin-types/ref-struct.md) article. ## Passing an argument by reference From b7da93f96a49dcb7e36d4a52803eb00beb1836c0 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 19 Sep 2022 10:45:09 -0400 Subject: [PATCH 16/16] fix snippet build issues namespace name changes --- .../keywords/snippets/AsyncExceptionExamples.cs | 2 +- .../keywords/snippets/GenericWhereConstraints.cs | 4 ++-- docs/csharp/language-reference/keywords/snippets/Program.cs | 2 +- .../keywords/snippets/ReadonlyKeywordExamples.cs | 2 +- .../keywords/snippets/RefKeywordsExceptions.cs | 2 +- .../language-reference/keywords/snippets/keywords.csproj | 2 +- docs/csharp/language-reference/keywords/snippets/usings.cs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/csharp/language-reference/keywords/snippets/AsyncExceptionExamples.cs b/docs/csharp/language-reference/keywords/snippets/AsyncExceptionExamples.cs index 4d1035eb70a4b..e1fae35f2153d 100644 --- a/docs/csharp/language-reference/keywords/snippets/AsyncExceptionExamples.cs +++ b/docs/csharp/language-reference/keywords/snippets/AsyncExceptionExamples.cs @@ -6,7 +6,7 @@ using System.Diagnostics; -namespace keywords +namespace Keywords { class AsyncExceptionExamples { diff --git a/docs/csharp/language-reference/keywords/snippets/GenericWhereConstraints.cs b/docs/csharp/language-reference/keywords/snippets/GenericWhereConstraints.cs index 8d342ef9698cd..73634507f559e 100644 --- a/docs/csharp/language-reference/keywords/snippets/GenericWhereConstraints.cs +++ b/docs/csharp/language-reference/keywords/snippets/GenericWhereConstraints.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Text; -using static keywords.UnmanagedExtensions; +using static Keywords.UnmanagedExtensions; -namespace keywords +namespace Keywords { // public class AGenericClass where T : IComparable { } diff --git a/docs/csharp/language-reference/keywords/snippets/Program.cs b/docs/csharp/language-reference/keywords/snippets/Program.cs index a799acf31d569..14aaf35839801 100644 --- a/docs/csharp/language-reference/keywords/snippets/Program.cs +++ b/docs/csharp/language-reference/keywords/snippets/Program.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -namespace keywords +namespace Keywords { class Program { diff --git a/docs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.cs b/docs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.cs index c99ed37792807..eb1d1f0bde431 100644 --- a/docs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.cs +++ b/docs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace keywords +namespace Keywords { // class Age diff --git a/docs/csharp/language-reference/keywords/snippets/RefKeywordsExceptions.cs b/docs/csharp/language-reference/keywords/snippets/RefKeywordsExceptions.cs index 3c9629b765027..6a1d38c7b3717 100644 --- a/docs/csharp/language-reference/keywords/snippets/RefKeywordsExceptions.cs +++ b/docs/csharp/language-reference/keywords/snippets/RefKeywordsExceptions.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Text; -namespace keywords +namespace Keywords { public class RefKeywordsExceptions { diff --git a/docs/csharp/language-reference/keywords/snippets/keywords.csproj b/docs/csharp/language-reference/keywords/snippets/keywords.csproj index d8b2fef7d5b06..459979bc2dea5 100644 --- a/docs/csharp/language-reference/keywords/snippets/keywords.csproj +++ b/docs/csharp/language-reference/keywords/snippets/keywords.csproj @@ -5,7 +5,7 @@ net7.0 enable true - keywords.Program + Keywords.Program preview diff --git a/docs/csharp/language-reference/keywords/snippets/usings.cs b/docs/csharp/language-reference/keywords/snippets/usings.cs index 12e131244328b..75ddcd8e9fbaa 100644 --- a/docs/csharp/language-reference/keywords/snippets/usings.cs +++ b/docs/csharp/language-reference/keywords/snippets/usings.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace keywords +namespace Keywords { public static class UsingStatements {