Skip to content

Conversation

gewarren
Copy link
Contributor

@gewarren gewarren commented Sep 30, 2025

> [!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:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This list got orphaned at some point.

@jskeet
Copy link

jskeet commented Oct 1, 2025

Thanks so much for this!

Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gewarren

This looks good, with a few small changes.

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 can't include an access modifier. Members with a default implementation can include any access modifier.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer true. Let's change it:

Suggested change
Interface members without an implementation can't include an access modifier. Members with a default implementation can include any access modifier.
Interface members without an implementation are `public` by default. Members with an implementation are `private` by default. Interface members can include any access modifier.

- [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)).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add clarifying comment:

Suggested change
- Explicit access modifiers (the default access is [`public`](access-modifiers.md)).
- Explicit access modifiers (the default access for abstract methods is [`public`](access-modifiers.md)).

## 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 cannot 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 link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contraction:

Suggested change
Interfaces cannot 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:

While it's a breaking change in the sense that it raises your minimum .NET version to .NET 6, 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. For these reasons, use judgment when adding a member to an existing interface.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding one more condition:

Suggested 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. For these reasons, use judgment when adding a member to an existing interface.
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Should adding a static (non-virtual, non-abstract) member to an interface be considered breaking?
3 participants