You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/core/compatibility/library-change-rules.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,16 +1,15 @@
1
1
---
2
2
title: .NET API changes that affect compatibility
3
3
description: Learn how .NET attempts to maintain compatibility for developers across .NET versions, and what kind of change is considered a breaking change.
4
-
ms.date: 05/12/2021
4
+
ms.date: 09/30/2025
5
5
ms.topic: article
6
6
---
7
7
# Change rules for compatibility
8
8
9
9
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:
10
10
11
11
- A large number of developers either originally developed or continue to develop .NET Framework applications. They expect consistent behavior across .NET implementations.
12
-
13
-
- .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.
12
+
- .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.
14
13
15
14
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.
16
15
@@ -122,9 +121,11 @@ Changes in this category modify the public surface area of a type. Most of the c
122
121
123
122
This includes removing or renaming a getter or setter from a property, as well as renaming or removing enumeration members.
124
123
125
-
- ❌ **DISALLOWED: Adding a member to an interface**
124
+
- ❓ **REQUIRES JUDGMENT: Adding a member to an interface**
125
+
126
+
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.
126
127
127
-
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.
128
+
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.
128
129
129
130
- ❌ **DISALLOWED: Changing the value of a public constant or enumeration member**
130
131
@@ -153,9 +154,8 @@ Changes in this category modify the public surface area of a type. Most of the c
153
154
- ❌ **DISALLOWED: Adding the [virtual](../../csharp/language-reference/keywords/virtual.md) keyword to a member**
154
155
155
156
While this often is not a breaking change because the C# compiler tends to emit [callvirt](<xref:System.Reflection.Emit.OpCodes.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:
156
-
157
-
- C# is not the only language that .NET targets.
158
157
158
+
- C# is not the only language that .NET targets.
159
159
- 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-)).
160
160
161
161
Making a method virtual means that the consumer code would often end up calling it non-virtually.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/keywords/interface.md
+26-23Lines changed: 26 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,47 +9,50 @@ helpviewer_keywords:
9
9
---
10
10
# :::no-loc text="interface"::: (C# Reference)
11
11
12
-
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).
12
+
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.
13
+
14
+
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.
15
+
16
+
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).
13
17
14
18
In the following example, class `ImplementationClass` must implement a method named `SampleMethod` that has no parameters and returns `void`.
For more information and examples, see [Interfaces](../../fundamentals/types/interfaces.md).
17
23
18
-
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.
24
+
## Access modifiers
19
25
20
-
Interface members without an implementation can't include an access modifier. Members with a default implementation can include any access modifier.
26
+
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.
21
27
22
-
## Example interface
28
+
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`).
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:
32
+
An interface declaration can contain the following members:
-[Static fields, methods, properties, indexers, and events](static.md).
43
+
-[Member declarations using the explicit interface implementation syntax](~/_csharplang/proposals/csharp-8.0/default-interface-methods.md#explicit-implementation-in-interfaces).
44
+
- Explicit access modifiers (the default access for abstract methods is [`public`](access-modifiers.md)).
32
45
33
46
## Default interface members
34
47
35
-
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.
48
+
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.
36
49
37
50
> [!IMPORTANT]
38
51
> Adding default interfaces members forces any `ref struct` that implements the interface to add an explicit declaration of that member.
-[Static fields, methods, properties, indexers, and events](static.md)
47
-
-[Member declarations using the explicit interface implementation syntax](~/_csharplang/proposals/csharp-8.0/default-interface-methods.md#explicit-implementation-in-interfaces).
48
-
- Explicit access modifiers (the default access is [`public`](access-modifiers.md)).
49
-
50
53
## Static abstract and virtual members
51
54
52
-
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 <xref:System.Numerics.INumber%601?displayProperty=nameWithType>. 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<T>` interface declares that `T` must implement `INumber<T>`. 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<int>`. 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.
55
+
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 <xref:System.Numerics.INumber%601?displayProperty=nameWithType>. 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<T>` interface declares that `T` must implement `INumber<T>`. 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<int>`. 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.
53
56
54
57
> [!IMPORTANT]
55
58
> 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
58
61
59
62
## Interface inheritance
60
63
61
-
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:
64
+
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:
Copy file name to clipboardExpand all lines: docs/csharp/whats-new/csharp-version-history.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -196,7 +196,7 @@ The C# 9 release continues the work to keep C# a modern, general-purpose program
196
196
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:
@@ -213,7 +213,7 @@ C# 8.0 is the first major C# release that specifically targets .NET Core. Some f
213
213
-[Stackalloc in nested expressions](../language-reference/operators/stackalloc.md)
214
214
-[Enhancement of interpolated verbatim strings](../language-reference/tokens/interpolated.md)
215
215
216
-
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.
216
+
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.
0 commit comments