diff --git a/docs/core/compatibility/library-change-rules.md b/docs/core/compatibility/library-change-rules.md index b804243da5064..a386daa4202fa 100644 --- a/docs/core/compatibility/library-change-rules.md +++ b/docs/core/compatibility/library-change-rules.md @@ -1,7 +1,7 @@ --- title: .NET API changes that affect compatibility description: Learn how .NET attempts to maintain compatibility for developers across .NET versions, and what kind of change is considered a breaking change. -ms.date: 05/12/2021 +ms.date: 09/30/2025 ms.topic: article --- # Change rules for compatibility @@ -9,8 +9,7 @@ ms.topic: article Throughout its history, .NET has attempted to maintain a high level of compatibility from version to version and across implementations of .NET. Although .NET 5 (and .NET Core) and later versions can be considered as a new technology compared to .NET Framework, two major factors limit the ability of this implementation of .NET to diverge from .NET Framework: - A large number of developers either originally developed or continue to develop .NET Framework applications. They expect consistent behavior across .NET implementations. - -- .NET Standard library projects allow developers to create libraries that target common APIs shared by .NET Framework and .NET 5 (and .NET Core) and later versions. Developers expect that a library used in a .NET 5 application should behave identically to the same library used in a .NET Framework application. +- .NET Standard library projects allow developers to create libraries that target common APIs shared by .NET Framework and .NET 5 (and .NET Core) and later versions. Developers expect that a library used in a .NET application should behave identically to the same library used in a .NET Framework application. Along with compatibility across .NET implementations, developers expect a high level of compatibility across versions of a given implementation of .NET. In particular, code written for an earlier version of .NET Core should run seamlessly on .NET 5 or a later version. In fact, many developers expect that the new APIs found in newly released versions of .NET should also be compatible with the pre-release versions in which those APIs were introduced. @@ -122,9 +121,11 @@ Changes in this category modify the public surface area of a type. Most of the c This includes removing or renaming a getter or setter from a property, as well as renaming or removing enumeration members. -- ❌ **DISALLOWED: Adding a member to an interface** +- ❓ **REQUIRES JUDGMENT: Adding a member to an interface** + + While it's a breaking change in the sense that it raises your minimum .NET version to .NET Core 3.0 (C# 8.0), which is when [default interface members](../../csharp/language-reference/keywords/interface.md#default-interface-members) (DIMs) were introduced, adding a static, non-abstract, non-virtual member to an interface is allowed. - If you [provide an implementation](../../csharp/advanced-topics/interface-implementation/default-interface-methods-versions.md), adding a new member to an existing interface won't necessarily result in compile failures in downstream assemblies. However, not all languages support default interface members (DIMs). Also, in some scenarios, the runtime can't decide which default interface member to invoke. For these reasons, adding a member to an existing interface is considered a breaking change. + If you [provide an implementation](../../csharp/advanced-topics/interface-implementation/default-interface-methods-versions.md), adding a new member to an existing interface won't necessarily result in compile failures in downstream assemblies. However, not all languages support DIMs. Also, in some scenarios, the runtime can't decide which default interface member to invoke. In some scenarios, interfaces are implemented by `ref struct` types. Because `ref struct` types can't be boxed, they can't be converted to interface types. Therefore, `ref struct` types must provide an implicit implementation for every interface member. They can't make use of the default implementation provided by the interface. For these reasons, use judgment when adding a member to an existing interface. - ❌ **DISALLOWED: Changing the value of a public constant or enumeration member** @@ -153,9 +154,8 @@ Changes in this category modify the public surface area of a type. Most of the c - ❌ **DISALLOWED: Adding the [virtual](../../csharp/language-reference/keywords/virtual.md) keyword to a member** While this often is not a breaking change because the C# compiler tends to emit [callvirt]() Intermediate Language (IL) instructions to call non-virtual methods (`callvirt` performs a null check, while a normal call doesn't), this behavior is not invariable for several reasons: - - - C# is not the only language that .NET targets. + - C# is not the only language that .NET targets. - The C# compiler increasingly tries to optimize `callvirt` to a normal call whenever the target method is non-virtual and is probably not null (such as a method accessed through the [?. null propagation operator](../../csharp/language-reference/operators/member-access-operators.md#null-conditional-operators--and-)). Making a method virtual means that the consumer code would often end up calling it non-virtually. diff --git a/docs/core/tools/dotnet-nuget-why.md b/docs/core/tools/dotnet-nuget-why.md index eb0cf8feebabf..fff89d4a24957 100644 --- a/docs/core/tools/dotnet-nuget-why.md +++ b/docs/core/tools/dotnet-nuget-why.md @@ -15,7 +15,7 @@ ms.date: 05/30/2024 ## Synopsis ```dotnetcli -dotnet nuget why [-f|--framework ] +dotnet nuget why [] [-f|--framework ] dotnet nuget why -h|--help ``` @@ -38,7 +38,10 @@ To use the command with projects that can't be restored with the .NET SDK, you c - **`PROJECT|SOLUTION`** - The project or solution file to operate on. If a directory is specified, the command searches the directory for a project or solution file. If more than one project or solution is found, an error is thrown. + The project or solution file to operate on. + If a directory is specified, the command searches the directory for a project or solution file. + If more than one project or solution is found, an error is thrown. + If no value is provided, the current working directory is used by default. - **`PACKAGE`** @@ -54,22 +57,22 @@ To use the command with projects that can't be restored with the .NET SDK, you c ## Examples -- Show the dependency graph for the package "System.Text.Json" for a given solution: +- Show the dependency graph for the package "System.Text.Json": ```dotnetcli - dotnet nuget why .\DotnetNuGetWhyPackage.sln System.Text.Json + dotnet nuget why System.Text.Json ``` ![Example: Solution with multiple projects](media/dotnet-nuget-why/dotnet-nuget-why-solution-with-multiple-projects.png) -- Show the dependency graph for the package "System.Text.Json" for a single project: +- Show the dependency graph for the package "System.Text.Json" for a specific project: ```dotnetcli - dotnet nuget why .\DotnetNuGetWhyPackage.csproj System.Text.Json + dotnet nuget why path/to/DotnetNuGetWhyPackage.csproj System.Text.Json ``` - Show the dependency graph for a specific target framework: ```dotnetcli - dotnet nuget why .\DotnetNuGetWhyPackage.csproj System.Text.Json --framework net6.0 + dotnet nuget why System.Text.Json --framework net6.0 ``` diff --git a/docs/csharp/language-reference/keywords/interface.md b/docs/csharp/language-reference/keywords/interface.md index d33e6c95ce708..22801588a779c 100644 --- a/docs/csharp/language-reference/keywords/interface.md +++ b/docs/csharp/language-reference/keywords/interface.md @@ -9,47 +9,50 @@ helpviewer_keywords: --- # :::no-loc text="interface"::: (C# Reference) -An interface defines a contract. Any [`class`](class.md), [`record`](../builtin-types/record.md) or [`struct`](../builtin-types/struct.md) that implements that contract must provide an implementation of the members defined in the interface. An interface may define a default implementation for members. It may also define [`static`](static.md) members in order to provide a single implementation for common functionality. Beginning with C# 11, an interface may define `static abstract` or `static virtual` members to declare that an implementing type must provide the declared members. Typically, `static virtual` methods declare that an implementation must define a set of [overloaded operators](../operators/operator-overloading.md). +An interface defines a contract. Any [`class`](class.md), [`record`](../builtin-types/record.md) or [`struct`](../builtin-types/struct.md) that implements that contract must provide an implementation of the members defined in the interface. + +An interface can define a [default implementation](#default-interface-members) for a member. It can also define [`static`](static.md) members to provide a single implementation for common functionality. + +Beginning with C# 11, an interface can define `static abstract` or `static virtual` members to declare that an implementing type must provide the declared members. Typically, `static virtual` methods declare that an implementation must define a set of [overloaded operators](../operators/operator-overloading.md). In the following example, class `ImplementationClass` must implement a method named `SampleMethod` that has no parameters and returns `void`. +[!code-csharp[csrefKeywordsTypes#14](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs#14)] + For more information and examples, see [Interfaces](../../fundamentals/types/interfaces.md). -A top-level interface, one declared in a namespace but not nested inside another type, can be declared `public` or `internal`. The default is `internal`. Nested interface declarations, those declared inside another type, can be declared using any access modifier. +## Access modifiers -Interface members without an implementation can't include an access modifier. Members with a default implementation can include any access modifier. +An interface can be a member of a namespace or a class. A top-level interface, one declared in a namespace but not nested inside another type, can be declared `public` or `internal`. The default is `internal`. Nested interface declarations, those declared inside another type, can be declared using any access modifier. -## Example interface +Interface members *without* an implementation (abstract members) are implicitly `public` and cannot have any other access modifier. Interface members *with* a default implementation are `private` by default if no access modifier is specified, but can be declared with any access modifier (`public`, `private`, `protected`, or `internal`). -[!code-csharp[csrefKeywordsTypes#14](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs#14)] +## Interface members -An interface can be a member of a namespace or a class. An interface declaration can contain declarations (signatures without any implementation) of the following members: +An interface declaration can contain the following members: -- [Methods](../../programming-guide/classes-and-structs/methods.md) -- [Properties](../../programming-guide/classes-and-structs/using-properties.md) -- [Indexers](../../programming-guide/indexers/using-indexers.md) -- [Events](event.md) +- [Methods](../../programming-guide/classes-and-structs/methods.md). +- [Properties](../../programming-guide/classes-and-structs/using-properties.md). +- [Indexers](../../programming-guide/indexers/using-indexers.md). +- [Events](event.md). +- [Constants](const.md). +- [Operators](../operators/operator-overloading.md). +- [A static constructor](../../programming-guide/classes-and-structs/constructors.md#static-constructors). +- [Nested types](../../programming-guide/classes-and-structs/nested-types.md). +- [Static fields, methods, properties, indexers, and events](static.md). +- [Member declarations using the explicit interface implementation syntax](~/_csharplang/proposals/csharp-8.0/default-interface-methods.md#explicit-implementation-in-interfaces). +- Explicit access modifiers (the default access for abstract methods is [`public`](access-modifiers.md)). ## Default interface members -These preceding member declarations typically don't contain a body. An interface member may declare a body. Member bodies in an interface are the *default implementation*. Members with bodies permit the interface to provide a "default" implementation for classes and structs that don't provide an overriding implementation. +Member declarations typically don't contain a body, however, an interface member can declare a body. Member bodies in an interface are the *default implementation*. Members with bodies permit the interface to provide a "default" implementation for classes and structs that don't provide an overriding implementation. > [!IMPORTANT] > Adding default interfaces members forces any `ref struct` that implements the interface to add an explicit declaration of that member. -An interface may include: - -- [Constants](const.md) -- [Operators](../operators/operator-overloading.md) -- [Static constructor](../../programming-guide/classes-and-structs/constructors.md#static-constructors). -- [Nested types](../../programming-guide/classes-and-structs/nested-types.md) -- [Static fields, methods, properties, indexers, and events](static.md) -- [Member declarations using the explicit interface implementation syntax](~/_csharplang/proposals/csharp-8.0/default-interface-methods.md#explicit-implementation-in-interfaces). -- Explicit access modifiers (the default access is [`public`](access-modifiers.md)). - ## Static abstract and virtual members -Beginning with C# 11, an interface may declare `static abstract` and `static virtual` members for all member types except fields. Interfaces can declare that implementing types must define operators or other static members. This feature enables generic algorithms to specify number-like behavior. You can see examples in the numeric types in the .NET runtime, such as . These interfaces define common mathematical operators that are implemented by many numeric types. The compiler must resolve calls to `static virtual` and `static abstract` methods at compile time. The `static virtual` and `static abstract` methods declared in interfaces don't have a runtime dispatch mechanism analogous to `virtual` or `abstract` methods declared in classes. Instead, the compiler uses type information available at compile time. Therefore, `static virtual` methods are almost exclusively declared in [generic interfaces](../../programming-guide/generics/generic-interfaces.md). Furthermore, most interfaces that declare `static virtual` or `static abstract` methods declare that one of the type parameters must [implement the declared interface](../../programming-guide/generics/constraints-on-type-parameters.md#type-arguments-implement-declared-interface). For example, the `INumber` interface declares that `T` must implement `INumber`. The compiler uses the type argument to resolve calls to the methods and operators declared in the interface declaration. For example, the `int` type implements `INumber`. When the type parameter `T` denotes the type argument `int`, the `static` members declared on `int` are invoked. Alternatively, when `double` is the type argument, the `static` members declared on the `double` type are invoked. +Beginning with C# 11, an interface can declare `static abstract` and `static virtual` members for all member types except fields. Interfaces can declare that implementing types must define operators or other static members. This feature enables generic algorithms to specify number-like behavior. You can see examples in the numeric types in the .NET runtime, such as . These interfaces define common mathematical operators that are implemented by many numeric types. The compiler must resolve calls to `static virtual` and `static abstract` methods at compile time. The `static virtual` and `static abstract` methods declared in interfaces don't have a runtime dispatch mechanism analogous to `virtual` or `abstract` methods declared in classes. Instead, the compiler uses type information available at compile time. Therefore, `static virtual` methods are almost exclusively declared in [generic interfaces](../../programming-guide/generics/generic-interfaces.md). Furthermore, most interfaces that declare `static virtual` or `static abstract` methods declare that one of the type parameters must [implement the declared interface](../../programming-guide/generics/constraints-on-type-parameters.md#type-arguments-implement-declared-interface). For example, the `INumber` interface declares that `T` must implement `INumber`. The compiler uses the type argument to resolve calls to the methods and operators declared in the interface declaration. For example, the `int` type implements `INumber`. When the type parameter `T` denotes the type argument `int`, the `static` members declared on `int` are invoked. Alternatively, when `double` is the type argument, the `static` members declared on the `double` type are invoked. > [!IMPORTANT] > Method dispatch for `static abstract` and `static virtual` methods declared in interfaces is resolved using the compile time type of an expression. If the runtime type of an expression is derived from a different compile time type, the static methods on the base (compile time) type will be called. @@ -58,7 +61,7 @@ You can try this feature by working with the tutorial on [static abstract member ## Interface inheritance -Interfaces may not contain instance state. While static fields are now permitted, instance fields aren't permitted in interfaces. [Instance auto-properties](../../programming-guide/classes-and-structs/auto-implemented-properties.md) aren't supported in interfaces, as they would implicitly declare a hidden field. This rule has a subtle effect on property declarations. In an interface declaration, the following code doesn't declare an automatically implemented property as it does in a `class` or `struct`. Instead, it declares a property that doesn't have a default implementation but must be implemented in any type that implements the interface: +Interfaces can't contain instance state. While static fields are now permitted, instance fields aren't permitted in interfaces. [Instance auto-properties](../../programming-guide/classes-and-structs/auto-implemented-properties.md) aren't supported in interfaces, as they would implicitly declare a hidden field. This rule has a subtle effect on property declarations. In an interface declaration, the following code doesn't declare an automatically implemented property as it does in a `class` or `struct`. Instead, it declares a property that doesn't have a default implementation but must be implemented in any type that implements the interface: ```csharp public interface INamed diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index 6d99a5b0c8341..30dbe02f6ebf6 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -196,7 +196,7 @@ The C# 9 release continues the work to keep C# a modern, general-purpose program C# 8.0 is the first major C# release that specifically targets .NET Core. Some features rely on new Common Language Runtime (CLR) capabilities, others on library types added only in .NET Core. C# 8.0 adds the following features and enhancements to the C# language: - [Readonly members](../language-reference/builtin-types/struct.md#readonly-instance-members) -- [Default interface methods](../language-reference/keywords/interface.md#default-interface-members) +- [Default interface members](../language-reference/keywords/interface.md#default-interface-members) - [Pattern matching enhancements](../language-reference/operators/patterns.md): - Switch expressions - Property patterns @@ -213,7 +213,7 @@ C# 8.0 is the first major C# release that specifically targets .NET Core. Some f - [Stackalloc in nested expressions](../language-reference/operators/stackalloc.md) - [Enhancement of interpolated verbatim strings](../language-reference/tokens/interpolated.md) -Default interface members require enhancements in the CLR. Those features were added in the CLR for .NET Core 3.0. Ranges and indexes, and asynchronous streams require new types in the .NET Core 3.0 libraries. Nullable reference types, while implemented in the compiler, is much more useful when libraries are annotated to provide semantic information regarding the null state of arguments and return values. Those annotations are being added in the .NET Core libraries. +Default interface members require enhancements in the CLR. Those features were added in the CLR for .NET Core 3.0. Ranges, indexes, and asynchronous streams require new types in the .NET Core 3.0 libraries. Nullable reference types, while implemented in the compiler, is much more useful when libraries are annotated to provide semantic information regarding the null state of arguments and return values. Those annotations are being added in the .NET Core libraries. ## C# version 7.3