Skip to content

Commit f1313e8

Browse files
Merge pull request #48002 from dotnet/main
Merge main into live
2 parents d53ff59 + fe08267 commit f1313e8

File tree

12 files changed

+327
-10
lines changed

12 files changed

+327
-10
lines changed

docs/core/compatibility/10.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af
107107
| [Default workload configuration from 'loose manifests' to 'workload sets' mode](sdk/10.0/default-workload-config.md) | Behavioral change | Preview 2 |
108108
| [`dotnet package list` performs restore](sdk/10.0/dotnet-package-list-restore.md) | Behavioral change | Preview 4 |
109109
| [`dotnet restore` audits transitive packages](sdk/10.0/nugetaudit-transitive-packages.md) | Behavioral change | Preview 3 |
110+
| [project.json not supported in `dotnet restore`](sdk/10.0/dotnet-restore-project-json-unsupported.md) | Source incompatible | Preview 7 |
110111
| [SHA-1 fingerprint support deprecated in `dotnet nuget sign`](sdk/10.0/dotnet-nuget-sign-sha1-deprecated.md) | Behavioral change | Preview 1 |
111112
| [MSBUILDCUSTOMBUILDEVENTWARNING escape hatch removed](sdk/10.0/custom-build-event-warning.md) | Behavioral change | Preview 1 |
112113
| [MSBuild custom culture resource handling](sdk/10.0/msbuild-custom-culture.md) | Behavioral change | Preview 1 |
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: "Breaking change - project.json is no longer supported in dotnet restore"
3+
description: "Learn about the breaking change in .NET 10 where dotnet restore no longer supports project.json based projects."
4+
ms.date: 08/16/2025
5+
ai-usage: ai-assisted
6+
ms.custom: https://github.com/dotnet/docs/issues/47968
7+
---
8+
9+
# project.json no longer supported in dotnet restore
10+
11+
Starting with .NET 10, the [`dotnet restore` command](../../../tools/dotnet-restore.md) no longer supports `project.json` based projects. Such projects are ignored during the restore operation.
12+
13+
## Version introduced
14+
15+
.NET 10 Preview 7
16+
17+
## Previous behavior
18+
19+
The `dotnet restore` command restored dependencies for `project.json` based projects.
20+
21+
## New behavior
22+
23+
The `dotnet restore` command ignores `project.json` based projects and no longer restores their dependencies.
24+
25+
## Type of breaking change
26+
27+
This change can affect [source compatibility](../../categories.md#source-compatibility).
28+
29+
## Reason for change
30+
31+
The `project.json` format was originally available only in .NET Core previews (through Preview 2 of .NET Core 1.0) and was completely replaced by PackageReference in 2017. The format has been marked as deprecated since 2017.
32+
33+
When the `project.json` format was replaced, users migrated these projects using the [`dotnet migrate`](../../../tools/dotnet-migrate.md) command, but that command was removed from the CLI in the .NET Core 3.0 SDK.
34+
35+
The removal of `project.json` support completes this transition and allows the .NET team to focus on delivering a better experience for PackageReference-based projects.
36+
37+
## Recommended action
38+
39+
Migrate your `project.json` projects to use PackageReference format instead.
40+
41+
If you have .NET Core based `project.json` projects, you can use older versions of the .NET SDK that still include the [`dotnet migrate` command](../../../tools/dotnet-migrate.md) to convert them to the modern project format.
42+
43+
For more information about migrating from `project.json`, see [Migrating from project.json to .csproj](/nuget/archive/project-json#migrate-projectjson-to-packagereference).
44+
45+
## Affected APIs
46+
47+
None.

docs/core/compatibility/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ items:
114114
href: sdk/10.0/dotnet-tool-pack-publish.md
115115
- name: "`dotnet restore` audits transitive packages"
116116
href: sdk/10.0/nugetaudit-transitive-packages.md
117+
- name: project.json not supported in `dotnet restore`
118+
href: sdk/10.0/dotnet-restore-project-json-unsupported.md
117119
- name: Default workload configuration from 'loose manifests' to 'workload sets' mode
118120
href: sdk/10.0/default-workload-config.md
119121
- name: "`dotnet package list` performs restore"

docs/csharp/fundamentals/types/records.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Record types"
33
description: Learn about C# record types and how to create them. A record is a class that provides value semantics.
4-
ms.date: 05/24/2023
4+
ms.date: 08/15/2025
55
helpviewer_keywords:
66
- "records [C#]"
77
- "C# language, records"
@@ -31,7 +31,7 @@ Immutability isn't appropriate for all data scenarios. [Entity Framework Core](/
3131

3232
## How records differ from classes and structs
3333

34-
The same syntax that [declares](classes.md#declaring-classes) and [instantiates](classes.md#creating-objects) classes or structs can be used with records. Just substitute the `class` keyword with the `record`, or use `record struct` instead of `struct`. Likewise, the same syntax for expressing inheritance relationships is supported by record classes. Records differ from classes in the following ways:
34+
The same syntax that [declares](classes.md#declaring-classes) and [instantiates](classes.md#creating-objects) classes or structs can be used with records. Just substitute the `class` keyword with the `record`, or use `record struct` instead of `struct`. Likewise, record classes support the same syntax for expressing inheritance relationships. Records differ from classes in the following ways:
3535

3636
* You can use [positional parameters](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) in a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) to create and instantiate a type with immutable properties.
3737
* The same methods and operators that indicate reference equality or inequality in classes (such as <xref:System.Object.Equals(System.Object)?displayProperty=nameWithType> and `==`), indicate [value equality or inequality](../../language-reference/builtin-types/record.md#value-equality) in records.
@@ -57,6 +57,8 @@ The following example demonstrates use of a `with` expression to copy an immutab
5757

5858
:::code language="csharp" source="./snippets/records/ImmutableRecord.cs" id="ImmutableRecord":::
5959

60+
In the preceding examples, all properties are independent. None of the properties are computed from other property values. A `with` expression first copies the existing record instance, then modifies any properties or fields specified in the `with` expression. Computed properties in `record` types should be computed on access, not initialized when the instance is created. Otherwise, a property could return the computed value based on the original instance, not the modified copy. If you must initialize a computed property rather than compute on access, you should consider a [`class`](./classes.md) instead of a record.
61+
6062
For more information, see [Records (C# reference)](../../language-reference/builtin-types/record.md).
6163

6264
## C# Language Specification

docs/csharp/language-reference/builtin-types/record.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Records"
33
description: Learn about the record modifier for class and struct types in C#. Records provide standard support for value based equality on instances of record types.
4-
ms.date: 02/05/2025
4+
ms.date: 08/15/2025
55
f1_keywords:
66
- "record_CSharpKeyword"
77
helpviewer_keywords:
@@ -146,6 +146,27 @@ If you need different copying behavior, you can write your own copy constructor
146146

147147
You can't override the clone method, and you can't create a member named `Clone` in any record type. The actual name of the clone method is compiler-generated.
148148

149+
> [!IMPORTANT]
150+
> In the preceding examples, all properties are independent. None of the properties are computed from other property values. A `with` expression first copies the existing record instance, then modifies any properties or fields specified in the `with` expression. Computed properties in `record` types should be computed on access, not initialized when the instance is created. Otherwise, a property could return the computed value based on the original instance, not the modified copy.
151+
152+
You ensure correctness on computed properties by computing the value on access, as shown in the following declaration:
153+
154+
:::code language="csharp" source="snippets/shared/RecordType.cs" id="WitherComputed":::
155+
156+
The preceding record type computes the `Distance` when accessed, as shown in the following example:
157+
158+
:::code language="csharp" source="snippets/shared/RecordType.cs" id="WitherComputedUsage":::
159+
160+
Contrast that with the following declaration, where the `Distance` property is computed and cached as part of the initialization of a new instance:
161+
162+
:::code language="csharp" source="snippets/shared/RecordType.cs" id="WitherInit":::
163+
164+
Because `Distance` is computed as part of initialization, the value is computed and cached before the `with` expression changes the value of `Y` in the copy. The result is that the distance is incorrect:
165+
166+
:::code language="csharp" source="snippets/shared/RecordType.cs" id="WitherInitUsage":::
167+
168+
The `Distance` computation isn't expensive to compute on each access. However, some computed properties might require access to more data or more extensive computation. In those cases, instead of a record, use a `class` type and compute the cached value when one of the components changes value.
169+
149170
## Built-in formatting for display
150171

151172
Record types have a compiler-generated <xref:System.Object.ToString%2A> method that displays the names and values of public properties and fields. The `ToString` method returns a string of the following format:

docs/csharp/language-reference/builtin-types/snippets/shared/RecordType.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public static void Examples()
2323
var p = new Point();
2424
(double x, double y, double z) = p;
2525

26+
Console.WriteLine("=================================================");
27+
ComputedWither.ExampleUsage.Example();
28+
2629
}
2730
// <PositionalRecord>
2831
public record Person(string FirstName, string LastName);
@@ -102,7 +105,7 @@ public static class PositionalAttributes
102105
/// map to the JSON elements "firstName" and "lastName" when
103106
/// serialized or deserialized.
104107
/// </remarks>
105-
public record Person([property: JsonPropertyName("firstName")] string FirstName,
108+
public record Person([property: JsonPropertyName("firstName")] string FirstName,
106109
[property: JsonPropertyName("lastName")] string LastName);
107110
// </PositionalAttributes>
108111

@@ -335,7 +338,8 @@ protected override bool PrintMembers(StringBuilder stringBuilder)
335338
if (base.PrintMembers(stringBuilder))
336339
{
337340
stringBuilder.Append(", ");
338-
};
341+
}
342+
;
339343
stringBuilder.Append($"Grade = {Grade}");
340344
return true;
341345
}
@@ -426,4 +430,47 @@ public static void Main()
426430
// </WithExpressionInheritance>
427431
}
428432
}
433+
434+
namespace ComputedWither
435+
{
436+
// <WitherComputed>
437+
public record Point(int X, int Y)
438+
{
439+
public double Distance => Math.Sqrt(X * X + Y * Y);
440+
}
441+
// </WitherComputed>
442+
443+
// <WitherInit>
444+
public record PointInit(int X, int Y)
445+
{
446+
public double Distance { get; } = Math.Sqrt(X * X + Y * Y);
447+
}
448+
// </WitherInit>
449+
450+
public static class ExampleUsage
451+
{
452+
public static void Example()
453+
{
454+
// <WitherComputedUsage>
455+
Point p1 = new Point(3, 4);
456+
Console.WriteLine($"Original point: {p1}");
457+
p1 = p1 with { Y = 8 };
458+
Console.WriteLine($"Modified point: {p1}");
459+
// Output:
460+
// Original point: Point { X = 3, Y = 4, Distance = 5 }
461+
// Modified point: Point { X = 3, Y = 8, Distance = 8.54400374531753 }
462+
// </WitherComputedUsage>
463+
464+
// <WitherInitUsage>
465+
PointInit pt1 = new PointInit(3, 4);
466+
Console.WriteLine($"Original point: {pt1}");
467+
pt1 = pt1 with { Y = 8 };
468+
Console.WriteLine($"Incorrect Modified point: {pt1}");
469+
// Output:
470+
// Original point: PointInit { X = 3, Y = 4, Distance = 5 }
471+
// Modified point: PointInit { X = 3, Y = 8, Distance = 5 }
472+
// </WitherInitUsage>
473+
}
474+
}
475+
}
429476
}

docs/csharp/language-reference/keywords/using-directive.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,14 @@ Analyzers issue diagnostics if you duplicate `global` using directives in differ
8282
The `using static` directive names a type whose static members and nested types you can access without specifying a type name. Its syntax is:
8383

8484
```csharp
85+
// not within a namespace
8586
using static <fully-qualified-type-name>;
8687
```
8788

8889
The `<fully-qualified-type-name>` is the name of the type whose static members and nested types can be referenced without specifying a type name. If you don't provide a fully qualified type name (the full namespace name along with the type name), C# generates compiler error [CS0246](../compiler-messages/assembly-references.md): "The type or namespace name 'type/namespace' couldn't be found (are you missing a using directive or an assembly reference?)".
8990

91+
If the `using static` directive is applied within the context of a namespace (either file-scoped or nested in a `namespace` block, it is not necessary to fully qualify the type.
92+
9093
The `using static` directive applies to any type that has static members (or nested types), even if it also has instance members. However, instance members can only be invoked through the type instance.
9194

9295
You can access static members of a type without having to qualify the access with the type name:

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ catch (ExceptionType [e]) when (expr)
2727

2828
where *expr* is an expression that evaluates to a Boolean value. If it returns `true`, the exception handler executes; if `false`, it does not.
2929

30+
Exception filters with the `when` keyword provide several advantages over traditional exception handling approaches, including better debugging support and performance benefits. For a detailed explanation of how exception filters preserve the call stack and improve debugging, see [Exception filters vs. traditional exception handling](../statements/exception-handling-statements.md#exception-filters-vs-traditional-exception-handling).
31+
3032
The following example uses the `when` keyword to conditionally execute handlers for an <xref:System.Net.Http.HttpRequestException> depending on the text of the exception message.
3133

3234
[!code-csharp[when-with-catch](~/samples/snippets/csharp/language-reference/keywords/when/catch.cs)]

docs/csharp/language-reference/operators/with-expression.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
2-
title: "with expression - create new objects that are modified copies of existing objects"
2+
title: "The with expression - create new objects that are modified copies of existing objects"
33
description: "Learn about a with expression that performs nondestructive mutation of C# records and structures. The `with` keyword provides the means to modify one or more properties in the new object."
4-
ms.date: 11/22/2024
4+
ms.date: 08/15/2025
55
f1_keywords:
66
- "with_CSharpKeyword"
77
helpviewer_keywords:
88
- "with expression [C#]"
99
- "with operator [C#]"
1010
---
11-
# with expression - Nondestructive mutation creates a new object with modified properties
11+
# The `with` expression - Nondestructive mutation creates a new object with modified properties
1212

1313
A `with` expression produces a copy of its operand with the specified properties and fields modified. You use the [object initializer](../../programming-guide/classes-and-structs/object-and-collection-initializers.md) syntax to specify what members to modify and their new values:
1414

@@ -20,7 +20,7 @@ The result of a `with` expression has the same run-time type as the expression's
2020

2121
:::code language="csharp" source="snippets/with-expression/InheritanceExample.cs" :::
2222

23-
In the case of a reference-type member, only the reference to a member instance is copied when an operand is copied. Both the copy and original operand have access to the same reference-type instance. The following example demonstrates that behavior:
23+
When a member is a reference type, only the reference to a member instance is copied when an operand is copied. Both the copy and original operand have access to the same reference-type instance. The following example demonstrates that behavior:
2424

2525
:::code language="csharp" source="snippets/with-expression/ExampleWithReferenceType.cs" :::
2626

@@ -32,6 +32,9 @@ Any record class type has the *copy constructor*. A *copy constructor* is a cons
3232

3333
You can't customize the copy semantics for structure types.
3434

35+
> [!IMPORTANT]
36+
> In the preceding examples, all properties are independent. None of the properties are computed from other property values. A `with` expression first copies the existing record instance, then modifies any properties or fields specified in the `with` expression. Computed properties in `record` types should be computed on access, not initialized when the instance is created. Otherwise, a property could return the computed value based on the original instance, not the modified copy. For more information, see the language reference article on [`record` types](../builtin-types/record.md#nondestructive-mutation).
37+
3538
## C# language specification
3639

3740
For more information, see the following sections of the [records feature proposal note](~/_csharplang/proposals/csharp-9.0/records.md):

docs/csharp/language-reference/statements/exception-handling-statements.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,43 @@ You can provide several `catch` clauses for the same exception type if they dist
9595

9696
If a `catch` clause has an exception filter, it can specify the exception type that is the same as or less derived than an exception type of a `catch` clause that appears after it. For example, if an exception filter is present, a `catch (Exception e)` clause doesn't need to be the last clause.
9797

98+
##### Exception filters vs. traditional exception handling
99+
100+
Exception filters provide significant advantages over traditional exception handling approaches. The key difference is **when** the exception handling logic is evaluated:
101+
102+
- **Exception filters (`when`)**: The filter expression is evaluated *before* the stack is unwound. This means the original call stack and all local variables remain intact during filter evaluation.
103+
- **Traditional `catch` blocks**: The catch block executes *after* the stack is unwound, potentially losing valuable debugging information.
104+
105+
Here's a comparison showing the difference:
106+
107+
:::code language="csharp" source="snippets/exception-handling-statements/WhenFilterExamples.cs" id="ExceptionFilterVsIfElse":::
108+
109+
## Advantages of exception filters
110+
111+
- **Better debugging experience**: Since the stack isn't unwound until a filter matches, debuggers can show the original point of failure with all local variables intact.
112+
- **Performance benefits**: If no filter matches, the exception continues propagating without the overhead of stack unwinding and restoration.
113+
- **Cleaner code**: Multiple filters can handle different conditions of the same exception type without requiring nested if-else statements.
114+
- **Logging and diagnostics**: You can examine and log exception details before deciding whether to handle the exception:
115+
116+
:::code language="csharp" source="snippets/exception-handling-statements/WhenFilterExamples.cs" id="DebuggingAdvantageExample":::
117+
118+
### When to use exception filters
119+
120+
Use exception filters when you need to:
121+
122+
- Handle exceptions based on specific conditions or properties.
123+
- Preserve the original call stack for debugging.
124+
- Log or examine exceptions before deciding whether to handle them.
125+
- Handle the same exception type differently based on context.
126+
127+
:::code language="csharp" source="snippets/exception-handling-statements/WhenFilterExamples.cs" id="MultipleConditionsExample":::
128+
129+
### Stack trace preservation
130+
131+
Exception filters preserve the original `ex.StackTrace` property. If a `catch` clause can't process the exception and re-throws, the original stack information is lost. The `when` filter doesn't unwind the stack, so if a `when` filter is `false`, the original stack trace isn't changed.
132+
133+
The exception filter approach is valuable in applications where preserving debugging information is crucial for diagnosing issues.
134+
98135
#### Exceptions in async and iterator methods
99136

100137
If an exception occurs in an [async function](../keywords/async.md), it propagates to the caller of the function when you [await](../operators/await.md) the result of the function, as the following example shows:

0 commit comments

Comments
 (0)