Skip to content

Commit 29c3905

Browse files
committed
Remaining open issues
- Fixes #43838: Add notes for collection expressions and using primary constructors. Include naming recommendations. - Fixes #43839 Update the overview of constructors to include information on primary constructors.
1 parent 040dba3 commit 29c3905

File tree

4 files changed

+83
-59
lines changed

4 files changed

+83
-59
lines changed

docs/csharp/fundamentals/coding-style/coding-conventions.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: ".NET Coding Conventions"
33
description: Learn about commonly used coding conventions in C#. Coding conventions create a consistent look to the code and facilitate copying, changing, and maintaining the code. This article also includes the docs repo coding guidelines
4-
ms.date: 01/14/2025
4+
ms.date: 01/15/2025
55
helpviewer_keyword:
66
- "coding conventions, C#"
77
- "Visual C#, coding conventions"
@@ -42,13 +42,13 @@ Code analysis produces warnings and diagnostics when the enabled rules are viola
4242
The following sections describe practices that the .NET docs team follows to prepare code examples and samples. In general, follow these practices:
4343

4444
- Utilize modern language features and C# versions whenever possible.
45-
- Avoid obsolete or outdated language constructs.
46-
- Only catch exceptions that can be properly handled; avoid catching generic exceptions.
45+
- Avoid outdated language constructs.
46+
- Only catch exceptions that can be properly handled; avoid catching general exceptions. For example, sample code should not catch the <xref:System.Exception?displayProperty=fullName> type without an exception filter.
4747
- Use specific exception types to provide meaningful error messages.
4848
- Use LINQ queries and methods for collection manipulation to improve code readability.
4949
- Use asynchronous programming with async and await for I/O-bound operations.
5050
- Be cautious of deadlocks and use <xref:System.Threading.Tasks.Task.ConfigureAwait%2A?DisplayProperty=nameWithType> when appropriate.
51-
- Use the language keywords for data types instead of the runtime types. For example, use `string` instead of <xref:System.String?DisplayProperty=fullName>, or `int` instead of <xref:System.Int32?displayProperty=fullName>.
51+
- Use the language keywords for data types instead of the runtime types. For example, use `string` instead of <xref:System.String?DisplayProperty=fullName>, or `int` instead of <xref:System.Int32?displayProperty=fullName>. This includes using the types `nint` and `nuint`.
5252
- Use `int` rather than unsigned types. The use of `int` is common throughout C#, and it's easier to interact with other libraries when you use `int`. Exceptions are for documentation specific to unsigned data types.
5353
- Use `var` only when a reader can infer the type from the expression. Readers view our samples on the docs platform. They don't have hover or tool tips that display the type of variables.
5454
- Write code with clarity and simplicity in mind.
@@ -66,15 +66,25 @@ More specific guidelines follow.
6666

6767
:::code language="csharp" source="./snippets/coding-conventions/program.cs" id="Snippet7":::
6868

69-
### Arrays
69+
- Prefer raw string literals to escape sequences or verbatim strings.
70+
- Use the expression based string interpolation rather than positional string interpolation.
7071

71-
- Use the concise syntax when you initialize arrays on the declaration line. In the following example, you can't use `var` instead of `string[]`.
72+
### Constructors and initialization
7273

73-
:::code language="csharp" source="./snippets/coding-conventions/program.cs" id="Snippet13a":::
74+
- Use Pascal case for primary constructor parameters on record types:
7475

75-
- If you use explicit instantiation, you can use `var`.
76+
:::code language="csharp" source="./snippets/coding-conventions/program.cs" id="PrimaryRecord":::
7677

77-
:::code language="csharp" source="./snippets/coding-conventions/program.cs" id="Snippet13b":::
78+
- Use camel case for primary constructor parameters on class and struct types:
79+
- Prefer required `init` properties to constructors to initialize fields.
80+
81+
:::code language="csharp" source="./snippets/coding-conventions/program.cs" id="PrimaryClass":::
82+
83+
### Arrays and collections
84+
85+
- Use collection expressions to initialize all collection types
86+
87+
:::code language="csharp" source="./snippets/coding-conventions/program.cs" id="Snippet13":::
7888

7989
### Delegates
8090

docs/csharp/fundamentals/coding-style/snippets/coding-conventions/program.cs

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,18 @@ static void Main(string[] args)
6161

6262
// Save snippet 4 and 5 for possible additions in program structure.
6363

64-
Name[] nameList = {new Name { FirstName = "Anderson", LastName = "Redmond" },
65-
new Name { FirstName = "Jones", LastName = "Seattle" },
66-
new Name { FirstName = "Anderson", LastName = "Redmond" }};
64+
Name[] nameList = [
65+
new Name { FirstName = "Anderson", LastName = "Redmond" },
66+
new Name { FirstName = "Jones", LastName = "Seattle" },
67+
new Name { FirstName = "Anderson", LastName = "Redmond" }
68+
];
6769
int n = 0;
6870

6971
//<snippet6>
7072
string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
7173
//</snippet6>
7274

73-
Console.WriteLine("{0}, {1}", nameList[n].LastName, nameList[n].FirstName);
75+
Console.WriteLine($"{nameList[n].LastName}, {nameList[n].FirstName}");
7476
Console.WriteLine(nameList[n].LastName + ", " + nameList[n].FirstName);
7577

7678
//<snippet7>
@@ -123,12 +125,9 @@ static void Main(string[] args)
123125
Console.WriteLine();
124126
//</snippet12>
125127

126-
//<snippet13a>
127-
string[] vowels1 = { "a", "e", "i", "o", "u" };
128-
//</snippet13a>
129-
//<snippet13b>
130-
var vowels2 = new string[] { "a", "e", "i", "o", "u" };
131-
//</snippet13b>
128+
//<snippet13>
129+
string[] vowels = [ "a", "e", "i", "o", "u" ];
130+
//</snippet13>
132131

133132
//<snippet15b>
134133
Del exampleDel2 = DelMethod;
@@ -152,10 +151,7 @@ static void Main(string[] args)
152151
}
153152
finally
154153
{
155-
if (bodyStyle != null)
156-
{
157-
((IDisposable)bodyStyle).Dispose();
158-
}
154+
bodyStyle?.Dispose();
159155
}
160156
//</snippet17a>
161157
//<snippet17b>
@@ -214,16 +210,10 @@ static void Main(string[] args)
214210

215211
ExampleClass.totalInstances = 1;
216212

217-
var Customers = new List<Customer>
218-
{
219-
new Customer { Name = "Jones", ID = 432, City = "Redmond" }
220-
};
213+
List<Customer> Customers = [ new Customer { Name = "Jones", ID = 432, City = "Redmond" } ];
221214

222215
// Check shop name to use this.
223-
var Distributors = new List<Distributor>
224-
{
225-
new Distributor { Name = "ShopSmart", ID = 11302, City = "Redmond" }
226-
};
216+
List<Distributor> Distributors = [ new Distributor { Name = "ShopSmart", ID = 11302, City = "Redmond" } ];
227217

228218
//<snippet25>
229219
//<snippet28>
@@ -335,20 +325,14 @@ public static int IncrementTotal()
335325
return totalInstances;
336326
}
337327

338-
public static int ResultSoFar()
339-
{
340-
return 0;
341-
}
328+
public static int ResultSoFar() => 0;
342329
}
343330

344331
class BaseClass
345332
{
346333
protected static int totalInstances;
347334

348-
static BaseClass()
349-
{
350-
totalInstances = 0;
351-
}
335+
static BaseClass() => totalInstances = 0;
352336

353337
public static int IncrementTotal()
354338
{
@@ -375,14 +359,13 @@ static void Main()
375359

376360
// Use a collection initializer to create the data source. Note that
377361
// each element in the list contains an inner sequence of scores.
378-
List<Student> students = new List<Student>
379-
{
380-
new Student {LastName="Omelchenko", Scores = [97, 72, 81, 60]},
381-
new Student {LastName="O'Donnell", Scores = [75, 84, 91, 39]},
382-
new Student {LastName="Mortensen", Scores = [88, 94, 65, 85]},
383-
new Student {LastName="Garcia", Scores = [97, 89, 85, 82]},
384-
new Student {LastName="Beebe", Scores = [35, 72, 91, 70]}
385-
};
362+
List<Student> students = [
363+
new Student {LastName="Omelchenko", Scores = [97, 72, 81, 60]},
364+
new Student {LastName="O'Donnell", Scores = [75, 84, 91, 39]},
365+
new Student {LastName="Mortensen", Scores = [88, 94, 65, 85]},
366+
new Student {LastName="Garcia", Scores = [97, 89, 85, 82]},
367+
new Student {LastName="Beebe", Scores = [35, 72, 91, 70]}
368+
];
386369

387370
//<snippet30>
388371
var scoreQuery = from student in students
@@ -395,12 +378,8 @@ where score > 90
395378
Console.WriteLine("scoreQuery:");
396379
foreach (var student in scoreQuery)
397380
{
398-
Console.WriteLine("{0} Score: {1}", student.Last, student.score);
381+
Console.WriteLine($"{student.Last} Score: {student.score}");
399382
}
400-
401-
// Keep the console window open in debug mode.
402-
Console.WriteLine("Press any key to exit.");
403-
Console.ReadKey();
404383
}
405384
}
406385
}
@@ -459,7 +438,7 @@ public class List<T> { /*...*/ }
459438
//</TypeParametersOne>
460439

461440
//<TypeParametersTwo>
462-
public int IComparer<T>() { return 0; }
441+
public int IComparer<T>() => 0;
463442
public delegate bool Predicate<T>(T item);
464443
public struct Nullable<T> where T : struct { /*...*/ }
465444
//</TypeParametersTwo>
@@ -475,3 +454,22 @@ public interface ISessionChannel<TSession>
475454
}
476455
}//WrapParameters
477456
}
457+
458+
namespace Constructors
459+
{
460+
// <PrimaryRecord>
461+
public record Person(string FirstName, string LastName);
462+
// </PrimaryRecord>
463+
464+
// <PrimaryClass>
465+
public class LabelledContainer<T>(string label)
466+
{
467+
public string Label { get; } = label;
468+
public required T Contents
469+
{
470+
get;
471+
init;
472+
}
473+
}
474+
// </PrimaryClass>
475+
}

docs/csharp/programming-guide/classes-and-structs/constructors.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
---
22
title: "Constructors"
33
description: A constructor in C# is called when a class or struct is created. Use constructors to set defaults, limit instantiation, and write flexible, easy-to-read code.
4-
ms.date: 04/06/2023
4+
ms.date: 01/15/2025
55
helpviewer_keywords:
66
- "constructors [C#]"
77
- "classes [C#], constructors"
88
- "C# language, constructors"
99
---
1010
# Constructors (C# programming guide)
1111

12-
Whenever an instance of a [class](../../language-reference/keywords/class.md) or a [struct](../../language-reference/builtin-types/struct.md) is created, its constructor is called. A class or struct may have multiple constructors that take different arguments. Constructors enable the programmer to set default values, limit instantiation, and write code that is flexible and easy to read. For more information and examples, see [Instance constructors](instance-constructors.md) and [Using constructors](using-constructors.md).
12+
A *constructor* is a method that is called by the runtime when an instance of a [class](../../language-reference/keywords/class.md) or a [struct](../../language-reference/builtin-types/struct.md) is created. A class or struct may have multiple constructors that take different arguments. Constructors enable you to set ensure that instances of the type are valid when created. For more information and examples, see [Instance constructors](instance-constructors.md) and [Using constructors](using-constructors.md).
1313

1414
There are several actions that are part of initializing a new instance. Those actions take place in the following order:
1515

@@ -20,23 +20,27 @@ There are several actions that are part of initializing a new instance. Those ac
2020
1. *The instance constructor runs*. The instance constructor for the type runs.
2121
1. *Object initializers run*. If the expression includes any object initializers, those run after the instance constructor runs. Object initializers run in the textual order.
2222

23-
The preceding actions take place when a new instance is initialized. If a new instance of a `struct` is set to its `default` value, all instance fields are set to 0.
23+
The preceding actions take place when an instance is created using the [`new` operator](../../language-reference//operators/new-operator.md). If a new instance of a `struct` is set to its `default` value, all instance fields are set to 0. Elements of an array are set to their default value of 0 or `null`.
2424

2525
If the [static constructor](static-constructors.md) hasn't run, the static constructor runs before any of the instance constructor actions take place.
2626

2727
## Constructor syntax
2828

29-
A constructor is a method whose name is the same as the name of its type. Its method signature includes only an optional [access modifier](./access-modifiers.md), the method name and its parameter list; it does not include a return type. The following example shows the constructor for a class named `Person`.
29+
A constructor is declared using the same as the name of its type. Its method signature can include an optional [access modifier](./access-modifiers.md), the method name and its parameter list; it does not include a return type. The following example shows the constructor for a class named `Person`.
3030

3131
:::code source="./snippets/constructors/Program.cs" id="InstanceCtor":::
3232

33-
If a constructor can be implemented as a single statement, you can use an [expression body definition](../statements-expressions-operators/expression-bodied-members.md). The following example defines a `Location` class whose constructor has a single string parameter named *name*. The expression body definition assigns the argument to the `locationName` field.
33+
If a constructor can be implemented as a single statement, you can use an [expression body member](../statements-expressions-operators/expression-bodied-members.md). The following example defines a `Location` class whose constructor has a single string parameter named *name*. The expression body definition assigns the argument to the `locationName` field.
3434

3535
:::code source="./snippets/constructors/Program.cs" id="ExpressionBodiedCtor":::
3636

37+
If a type requires a parameter to create an instance, you can use a *primary constructor* to indicate that one or more arguments are required to instantiate the type, as shown in the following example:
38+
39+
:::code source="./snippets/constructors/Program.cs" id="PrimaryCtor":::
40+
3741
## Static constructors
3842

39-
The previous examples have all shown instance constructors, which create a new object. A class or struct can also have a static constructor, which initializes static members of the type. Static constructors are parameterless. If you don't provide a static constructor to initialize static fields, the C# compiler initializes static fields to their default value as listed in the [Default values of C# types](../../language-reference/builtin-types/default-values.md) article.
43+
The previous examples have shown instance constructors, which create a new object. A class or struct can also declare a static constructor, which initializes static members of the type. Static constructors are parameterless. If you don't provide a static constructor to initialize static fields, the C# compiler initializes static fields to their default value as listed in the [Default values of C# types](../../language-reference/builtin-types/default-values.md) article.
4044

4145
The following example uses a static constructor to initialize a static field.
4246

docs/csharp/programming-guide/classes-and-structs/snippets/constructors/Program.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,15 @@ public string Name
6363
}
6464
// </ExpressionBodiedCtor>
6565

66+
// <PrimaryCtor>
67+
public class LabelledContainer<T>(string label)
68+
{
69+
public string Label { get; } = label;
70+
public required T Contents
71+
{
72+
get;
73+
init;
74+
}
75+
}
76+
// </PrimaryCtor>
77+

0 commit comments

Comments
 (0)