Skip to content

Commit b474c82

Browse files
committed
Add field backed properties to lang reference
Add the field backed properties updates to property articles in the language reference. While doing this, update the relevant articles to lead with automatically implemented properties, followed by field backed, then expression bodied, and finally fully implemented property accessors.
1 parent 8b79865 commit b474c82

File tree

16 files changed

+167
-92
lines changed

16 files changed

+167
-92
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
author: BillWagner
3+
ms.author: wiwagn
4+
ms.topic: include
5+
ms.date: 10/30/2024
6+
---
7+
8+
> [!IMPORTANT]
9+
>
10+
> The `field` keyword is a preview feature in C# 13. You must be using .NET 9 and set your `<LangVersion>` element to `preview` in your project file in order to use the `field` contextual keyword.

docs/csharp/language-reference/compiler-messages/partial-declarations.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,10 @@ The following warning indicates a signature difference in the declaring and impl
229229

230230
- **CS9256**: *Partial property declarations have signature differences.*
231231

232-
A partial property or indexer must have both a *declaring declaration* and an *implementing declaration*. The signatures for both declarations must match. Because the *declaring declaration* uses the same syntax as an automatically implemented property, the *implementing declaration* can't be an automatically implemented property. The accessors must have bodies.
232+
A partial property or indexer must have both a *declaring declaration* and an *implementing declaration*. The signatures for both declarations must match. Because the *declaring declaration* uses the same syntax as an automatically implemented property, the *implementing declaration* can't be an automatically implemented property. The accessors must have at least one accessor body. Beginning in C# 13, you can use the [`field`](../keywords/field.md) keyword to declare one accessor using a concise syntax:
233+
234+
```csharp
235+
public partial int ImplementingDeclaration { get => field; set; }
236+
```
237+
238+
[!INCLUDE[field-preview](../../includes/field-preview.md)]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
description: "The `field` contextual keyword - access the compiler generated backing field for a property"
3+
title: "The `field` contextual keyword"
4+
ms.date: 10/30/2024
5+
f1_keywords:
6+
- "field_CSharpKeyword"
7+
helpviewer_keywords:
8+
- "field keyword [C#]"
9+
---
10+
# `field` - Field backed property declarations
11+
12+
[!INCLUDE[field-preview](../../includes/field-preview.md)]
13+
14+
The contextual keyword `field`, added as a preview feature in C# 13, can be used in a property accessor to access the compiler generated backing field of a property. This syntax enables you to define the body of a `get` or `set` accessor and let the compiler generate the other accessor as it would in an automatically implemented property.
15+
16+
The addition of the `field` contextual keywords provides a smooth path to add benefits such as range checking to an automatically implemented property. This practice is shown in the following example:
17+
18+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="FieldBackedProperty":::
19+
20+
You might implement the `Hours` property as an automatically implemented property. Then, you discover that you want to protect against a negative value. You use `field` and provide range checking in the `set` accessor. You don't need to declare the backing field by hand and provide a body for the `get` accessor.
21+
22+
For more information, see the [Properties](../../programming-guide/classes-and-structs/properties.md) and [Indexers](../../programming-guide/indexers/index.md) articles.
23+
24+
## C# language specification
25+
26+
[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]

docs/csharp/language-reference/keywords/get.md

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,42 @@
11
---
22
description: "The C# get keyword declares a get accessor in a property or indexer. It defines the code to retrieve the value of the property or indexed property."
3-
title: "get keyword: property accessor"
4-
ms.date: 08/15/2024
3+
title: "The get keyword: property accessor"
4+
ms.date: 10/30/2024
55
f1_keywords:
66
- "get_CSharpKeyword"
77
- "get"
88
helpviewer_keywords:
99
- "get keyword [C#]"
1010
---
11-
# get (C# Reference)
11+
# The `get` keyword
1212

13-
The `get` keyword defines an *accessor* method in a property or indexer that returns the property value or the indexer element. For more information, see [Properties](../../programming-guide/classes-and-structs/properties.md), [Automatically implemented Properties](../../programming-guide/classes-and-structs/automatically implemented-properties.md), and [Indexers](../../programming-guide/indexers/index.md).
14-
15-
The following example defines both a `get` and a `set` accessor for a property named `Seconds`. It uses a private field named `_seconds` to back the property value.
16-
17-
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetAccessors":::
18-
19-
Often, the `get` accessor consists of a single statement that returns a value, as it did in the previous example. You can implement the `get` accessor as an expression-bodied member. The following example implements both the `get` and the `set` accessor as expression-bodied members.
20-
21-
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetExpressions":::
13+
The `get` keyword defines an *accessor* method in a property or indexer that returns the property value or the indexer element. For more information, see [Properties](../../programming-guide/classes-and-structs/properties.md), [Automatically implemented Properties](../../programming-guide/classes-and-structs/automatically implemented-properties.md), and [Indexers](../../programming-guide/indexers/index.md).
2214

2315
For simple cases in which a property's `get` and `set` accessors perform no other operation than setting or retrieving a value in a private backing field, you can take advantage of the C# compiler's support for automatically implemented properties. The following example implements `Hours` as an automatically implemented property.
24-
16+
2517
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="AutoImplementedProperties":::
26-
18+
2719
> [!IMPORTANT]
2820
> Automatically implemented properties aren't allowed for [interface property declarations](../../programming-guide/classes-and-structs/interface-properties.md) or the implementing declaration for a [partial property](./partial-member.md). The compiler interprets syntax matching an automatically implemented property as the declaring declaration, not an implementing declaration.
2921
22+
Often, the `get` accessor consists of a single statement that returns a value, as it did in the previous example. You can implement the `get` accessor as an expression-bodied member. The following example implements both the `get` and the `set` accessor as expression-bodied members.
23+
24+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetExpressions":::
25+
26+
You might find that you need to implement one of the accessor bodies. You can use a field backed property to let the compiler generate one accessor while you write the other by hand. You use the `field` keyword, added as a preview feature in C# 13, to access the compiler generated backing field:
27+
28+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="FieldBackedProperty":::
29+
30+
[!INCLUDE[field-preview](../../includes/field-preview.md)]
31+
32+
The following example defines both a `get` and a `set` accessor for a property named `Seconds`. It uses a private field named `_seconds` to back the property value.
33+
34+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetAccessors":::
35+
3036
## C# Language Specification
3137

32-
[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]
33-
38+
[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]
39+
3440
## See also
3541

3642
- [C# Keywords](./index.md)

docs/csharp/language-reference/keywords/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ A contextual keyword is used to provide a specific meaning in the code, but it i
125125
[`equals`](equals.md)
126126
:::column-end:::
127127
:::column:::
128+
[`field`](field.md)
128129
[`file`](file.md)
129130
[`from`](from-clause.md)
130131
[`get`](get.md)
Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,43 @@
11
---
2-
description: "init keyword - C# Reference"
3-
title: "init keyword"
2+
description: "The `init` keyword is used to declare a `set` accessor that can only be called during an object's initialization: either by a constructor or as part of an object initializer."
3+
title: "The init keyword - init only properties"
44
ms.date: 12/06/2023
55
f1_keywords:
66
- "init"
77
- "init_CSharpKeyword"
88
helpviewer_keywords:
99
- "init keyword [C#]"
1010
---
11-
# init (C# Reference)
11+
# The `init` keyword (C# Reference)
1212

1313
The `init` keyword defines an *accessor* method in a property or indexer. An init-only setter assigns a value to the property or the indexer element **only** during object construction. An `init` enforces immutability, so that once the object is initialized, it can't be changed. An `init` accessor enables calling code to use an [object initializer](../../programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer.md) to set the initial value. As a contrast, an
1414
[automatically implemented property](../../programming-guide/classes-and-structs/auto-implemented-properties.md) with only a `get` setter must be initialized by calling a constructor. A property with a `private set` accessor can be modified after construction, but only in the class.
1515

16-
The following example defines both a `get` and an `init` accessor for a property named `YearOfBirth`. It uses a private field named `_yearOfBirth` to back the property value.
16+
The following code demonstrates an `init` accessor in an automatically implemented property:
1717

18-
:::code language="csharp" source="snippets/InitExample1.cs":::
18+
:::code language="csharp" source="snippets/InitExample2.cs":::
1919

20-
Often, the `init` accessor consists of a single statement that assigns a value, as it did in the previous example. Because of `init`, the following **doesn't** work:
20+
You might need to implement one of the accessors to provide parameter validation. You can do that using the `field` keyword, introduced as a preview feature in C# 13. The `field` keyword accesses the compiler generated backing field for that property. The following example shows a property where the `init` accessor validates the range of the `value` parameter"
2121

22-
```csharp
23-
var john = new Person_InitExample
24-
{
25-
YearOfBirth = 1984
26-
};
22+
:::code language="csharp" source="snippets/InitExample5.cs":::
2723

28-
john.YearOfBirth = 1926; //Not allowed, as its value can only be set once in the constructor
29-
```
24+
[!INCLUDE[field-preview](../../includes/field-preview.md)]
3025

31-
An `init` accessor doesn't force callers to set the property. Instead, it allows callers to use an object initializer while prohibiting later modification. You can add the [`required`](required.md) modifier to force callers to set a property. The following example shows an `init` only property with a nullable value type as its backing field. If a caller doesn't initialize the `YearOfBirth` property, that property will have the default `null` value:
26+
The `init` accessor can be used as an expression-bodied member. Example:
3227

33-
:::code language="csharp" source="./snippets/InitNullablityExample.cs" id="Snippet4":::
28+
:::code language="csharp" source="snippets/InitExample3.cs":::
3429

35-
To force callers to set an initial non-null value, you add the `required` modifier, as shown in the following example:
30+
The following example defines both a `get` and an `init` accessor for a property named `YearOfBirth`. It uses a private field named `_yearOfBirth` to back the property value.
3631

37-
:::code language="csharp" source="./snippets/InitNullablityExample.cs" id="SnippetNonNullable":::
32+
:::code language="csharp" source="snippets/InitExample1.cs":::
3833

39-
The `init` accessor can be used as an expression-bodied member. Example:
34+
An `init` accessor doesn't force callers to set the property. Instead, it allows callers to use an object initializer while prohibiting later modification. You can add the [`required`](required.md) modifier to force callers to set a property. The following example shows an `init` only property with a nullable value type as its backing field. If a caller doesn't initialize the `YearOfBirth` property, that property has the default `null` value:
4035

41-
:::code language="csharp" source="snippets/InitExample3.cs":::
42-
43-
The `init` accessor can also be used in autoimplemented properties, as the following example code demonstrates:
36+
:::code language="csharp" source="./snippets/InitNullablityExample.cs" id="Snippet4":::
4437

45-
:::code language="csharp" source="snippets/InitExample2.cs":::
38+
To force callers to set an initial non-null value, you add the `required` modifier, as shown in the following example:
39+
40+
:::code language="csharp" source="./snippets/InitNullablityExample.cs" id="SnippetNonNullable":::
4641

4742
The following example shows the distinction between a `private set`, read only, and `init` property. Both the private set version and the read only version require callers to use the added constructor to set the name property. The `private set` version allows a person to change their name after the instance is constructed. The `init` version doesn't require a constructor. Callers can initialize the properties using an object initializer:
4843

@@ -56,5 +51,4 @@ The following example shows the distinction between a `private set`, read only,
5651

5752
## See also
5853

59-
- [C# Keywords](index.md)
6054
- [Properties](../../programming-guide/classes-and-structs/properties.md)
Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,42 @@
11
---
22
description: "The C# set keyword declares a set accessor in a property or indexer. It defines the code to set the value of the property or indexed property."
3-
title: "set keyword: property accessor"
4-
ms.date: 08/15/2024
3+
title: "The `set` keyword: property accessor"
4+
ms.date: 10/30/2024
55
f1_keywords:
66
- "set"
77
- "set_CSharpKeyword"
88
helpviewer_keywords:
99
- "set keyword [C#]"
1010
---
11-
# set (C# Reference)
11+
# The set keyword (C# Reference)
1212

1313
The `set` keyword defines an *accessor* method in a property or indexer that assigns a value to the property or the indexer element. For more information and examples, see [Properties](../../programming-guide/classes-and-structs/properties.md), [Automatically implemented properties](../../programming-guide/classes-and-structs/auto-implemented-properties.md), and [Indexers](../../programming-guide/indexers/index.md).
1414

15-
The following example defines both a `get` and a `set` accessor for a property named `Seconds`. It uses a private field named `_seconds` to back the property value.
15+
For simple cases in which a property's `get` and `set` accessors perform no other operation than setting or retrieving a value in a private backing field, you can use automatically implemented properties. The following example implements `Hours` as an automatically implemented property.
1616

17-
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetAccessors":::
17+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="AutoImplementedProperties":::
18+
19+
> [!IMPORTANT]
20+
> Automatically implemented properties aren't allowed for [interface property declarations](../../programming-guide/classes-and-structs/interface-properties.md) or the implementing declaration for a [partial property](./partial-member.md). The compiler interprets syntax matching an automatically implemented property as the declaring declaration, not an implementing declaration.
21+
22+
You might find that you need to implement one of the accessor bodies. The `field` keyword, added as a preview feature in C# 13 declares a field backed property. You can use a field backed property to let the compiler generate one accessor while you write the other by hand. You use the `field` keyword to access the compiler generated backing field:
23+
24+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="FieldBackedProperty":::
25+
26+
[!INCLUDE[field-preview](../../includes/field-preview.md)]
1827

1928
Often, the `set` accessor consists of a single statement that assigns a value, as it did in the previous example. You can implement the `set` accessor as an expression-bodied member. The following example implements both the `get` and the `set` accessors as expression-bodied members.
2029

2130
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetExpressions":::
22-
23-
For simple cases in which a property's `get` and `set` accessors perform no other operation than setting or retrieving a value in a private backing field, you can take advantage of the C# compiler's support for automatically implemented properties. The following example implements `Hours` as an automatically implemented property.
2431

25-
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="AutoImplementedProperties":::
32+
The following example defines both a `get` and a `set` accessor for a property named `Seconds`. It uses a private field named `_seconds` to back the property value.
2633

27-
> [!IMPORTANT]
28-
> Automatically implemented properties aren't allowed for [interface property declarations](../../programming-guide/classes-and-structs/interface-properties.md) or the implementing declaration for a [partial property](./partial-member.md). The compiler interprets syntax matching an automatically implemented property as the declaring declaration, not an implementing declaration.
34+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetAccessors":::
2935

3036
## C# language specification
3137

3238
[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]
3339

3440
## See also
3541

36-
- [C# Keywords](index.md)
3742
- [Properties](../../programming-guide/classes-and-structs/properties.md)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Person_InitExampleFieldProperty
2+
{
3+
public int YearOfBirth
4+
{
5+
get;
6+
init
7+
{
8+
field = (YearOfBirth <= DateTime.Now.Year)
9+
? value
10+
: throw new ArgumentOutOfRangeException(nameof(value), "Year of birth can't be in the future");
11+
}
12+
}
13+
}

docs/csharp/language-reference/keywords/snippets/PropertyAccessors.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,15 @@ class TimePeriod3
3939
public double Hours { get; set; }
4040
}
4141
// </AutoImplementedProperties>
42+
43+
// <FieldBackedProperty>
44+
class TimePeriod4
45+
{
46+
public double Hours {
47+
get;
48+
set => field = (value >= 0)
49+
? value
50+
: throw new ArgumentOutOfRangeException(nameof(value), "The value must not be negative");
51+
}
52+
}
53+
// </FieldBackedProperty>
Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
---
2-
description: "value contextual keyword - C# Reference"
3-
title: "value contextual keyword"
4-
ms.date: 07/20/2015
2+
description: "The token `value` is an implicit parameter to the `set` accessor for indexers or properties. It represents the parameter to the set accessor."
3+
title: "The `value` implicit parameter"
4+
ms.date: 10/30/2024
55
f1_keywords:
66
- "value_CSharpKeyword"
77
helpviewer_keywords:
88
- "value keyword [C#]"
9-
ms.assetid: c99d6468-687f-4a46-89b4-a95e1b00bf6d
109
---
11-
# value (C# Reference)
10+
# The `value` implicit parameter
1211

13-
The contextual keyword `value` is used in the `set` accessor in [property](../../programming-guide/classes-and-structs/properties.md) and [indexer](../../programming-guide/indexers/index.md) declarations. It is similar to an input parameter of a method. The word `value` references the value that client code is attempting to assign to the property or indexer. In the following example, `MyDerivedClass` has a property called `Name` that uses the `value` parameter to assign a new string to the backing field `name`. From the point of view of client code, the operation is written as a simple assignment.
12+
The implicit parameter `value` is used in the `set` accessor in [property](../../programming-guide/classes-and-structs/properties.md) and [indexer](../../programming-guide/indexers/index.md) declarations. It's an input parameter of a method. The word `value` references the value that client code is attempting to assign to the property or indexer. In the following example, `MyDerivedClass` has a property called `Name` that uses the `value` parameter to assign a new string to the backing field `name`. From the point of view of client code, the operation is written as a simple assignment.
1413

15-
[!code-csharp[csrefKeywordsModifiers#26](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsModifiers/CS/csrefKeywordsModifiers.cs#26)]
14+
:::code language="csharp" source="./snippets/PropertyAccessors.cs" id="GetSetExpressions":::
1615

1716
For more information, see the [Properties](../../programming-guide/classes-and-structs/properties.md) and [Indexers](../../programming-guide/indexers/index.md) articles.
1817

1918
## C# language specification
2019

2120
[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]
22-
23-
## See also
24-
25-
- [C# Keywords](index.md)

0 commit comments

Comments
 (0)