Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1612676
Allow interfaces as well
RexJaeschke Dec 5, 2022
ce1962b
support default interface function members
RexJaeschke Dec 5, 2022
25243b4
support default interface function members
RexJaeschke Dec 5, 2022
75567df
Update classes.md
RexJaeschke Dec 5, 2022
3ce3ccd
Update interfaces.md
RexJaeschke Dec 5, 2022
ed7d7c3
Update interfaces.md
RexJaeschke Dec 5, 2022
3086454
add annotation to new examples
RexJaeschke Jan 22, 2023
1b8a84e
first pass at fixing references
BillWagner Sep 25, 2023
e056252
find link errors part 2
BillWagner Sep 25, 2023
edcbd60
word converter warnings
BillWagner Sep 25, 2023
8fad8fa
minor tweaks
RexJaeschke Aug 25, 2024
d54fd4c
Fix editorial nits
RexJaeschke Nov 12, 2024
4a3dcf7
fix link
RexJaeschke May 28, 2025
a811a33
fix link
RexJaeschke May 28, 2025
f4f700e
Move interface descriptions to interfaces.
BillWagner Jul 21, 2025
22a41a3
Apply suggestions from code review
BillWagner Jul 21, 2025
a026967
edit pass on interfaces
BillWagner Jul 22, 2025
5bd2d4b
Rewrite most specific implementation rule
BillWagner Jul 23, 2025
3b99e44
lint issues
BillWagner Jul 25, 2025
696002b
Apply suggestions from code review
BillWagner Aug 20, 2025
8abcd9f
Respond to previous meeting feedback
BillWagner Aug 21, 2025
17865d0
fix grammar and test issues
BillWagner Aug 22, 2025
5ee6231
final pass at comments
BillWagner Aug 22, 2025
23212e5
Apply suggestions from code review
BillWagner Sep 2, 2025
294c1aa
review comments, plus some noodling
BillWagner Sep 2, 2025
b7f40b1
Add normative rules for interface member resolution
BillWagner Sep 3, 2025
a9c759c
first set of post-meeting updates.
BillWagner Sep 9, 2025
b7b025e
respond to review feedback.
BillWagner Sep 10, 2025
28e3391
Clarify more on access to interface members
BillWagner Sep 10, 2025
0b58bdd
Apply suggestions from code review
BillWagner Sep 11, 2025
96e844d
Merge branch 'draft-v8' into default-interface-function-members
BillWagner Sep 11, 2025
f424d4f
update anchor
BillWagner Sep 11, 2025
0c039de
update xrefs
BillWagner Sep 11, 2025
2eb6fe0
more anchor cleanup
BillWagner Sep 11, 2025
53f2bab
Update grammar tests for DIM
BillWagner Sep 15, 2025
3d198d4
mostly grammar edits
BillWagner Sep 25, 2025
a2302e6
Updates from review at 9/25 meeting
BillWagner Sep 25, 2025
9f75cf4
lint
BillWagner Sep 25, 2025
7b843a2
Address review comments
BillWagner Sep 26, 2025
c4c511b
Apply suggestions from code review
BillWagner Sep 29, 2025
709682e
Edits per review
BillWagner Sep 30, 2025
04150a2
fix test
BillWagner Sep 30, 2025
ef92d6e
fix build issue.
BillWagner Oct 2, 2025
acfdffe
Update rules for lookup and mapping
BillWagner Oct 2, 2025
5bb783c
Apply suggestions from code review
BillWagner Oct 22, 2025
20b278c
Apply suggestions from code review
BillWagner Oct 22, 2025
1d25821
Apply suggestions from code review
BillWagner Oct 22, 2025
aa22e86
Apply suggestions from code review
BillWagner Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions standard/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ There are several different types of declaration spaces, as described in the fol
- Within all compilation units of a program, *namespace_member_declaration*s with no enclosing *namespace_declaration* are members of a single combined declaration space called the ***global declaration space***.
- Within all compilation units of a program, *namespace_member_declaration*s within *namespace_declaration*s that have the same fully qualified namespace name are members of a single combined declaration space.
- Each *compilation_unit* and *namespace_body* has an ***alias declaration space***. Each *extern_alias_directive* and *using_alias_directive* of the *compilation_unit* or *namespace_body* contributes a member to the alias declaration space ([§14.5.2](namespaces.md#1452-using-alias-directives)).
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§16.2.4](structs.md#1624-partial-modifier)). Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§16.2.4](structs.md#1624-partial-modifier)). Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class, struct, or interface cannot contain a member declaration with the same name as the class, struct, or interface. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
- Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s.
- Each enumeration declaration creates a new declaration space. Names are introduced into this declaration space through *enum_member_declarations*.
- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set accessor for a property or an indexer introduces the name `value` as a parameter. The body of the function member, anonymous function, or local function, if any, is considered to be nested within the local variable declaration space. When a local variable declaration space and a nested local variable declaration space contain elements with the same name, within the scope of the nested local name, the outer local name is hidden ([§7.7.1](basic-concepts.md#771-general)) by the nested local name.
Expand Down Expand Up @@ -268,7 +268,7 @@ When access to a particular member is allowed, the member is said to be ***acces
The ***declared accessibility*** of a member can be one of the following:

- Public, which is selected by including a `public` modifier in the member declaration. The intuitive meaning of `public` is “access not limited”.
- Protected, which is selected by including a `protected` modifier in the member declaration. The intuitive meaning of `protected` is “access limited to the containing class or types derived from the containing class”.
- Protected, which is selected by including a `protected` modifier in the member declaration. The intuitive meaning of `protected` is “access limited to the containing class or interface, or classes or interfaces derived from the containing type”.
- Internal, which is selected by including an `internal` modifier in the member declaration. The intuitive meaning of `internal` is “access limited to this assembly”.
- Protected internal, which is selected by including both a `protected` and an `internal` modifier in the member declaration. The intuitive meaning of `protected internal` is “accessible within this assembly as well as types derived from the containing class”.
- Private protected, which is selected by including both a `private` and a `protected` modifier in the member declaration. The intuitive meaning of `private protected` is “accessible within this assembly by the containing class and types derived from the containing class.”
Expand Down Expand Up @@ -402,7 +402,7 @@ As described in [§7.4](basic-concepts.md#74-members), all members of a base cla

### 7.5.4 Protected access

When a `protected` or `private protected` instance member is accessed outside the program text of the class in which it is declared, and when a `protected internal` instance member is accessed outside the program text of the program in which it is declared, the access shall take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place *through* an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.
When a `protected` or `private protected` instance member is accessed outside the program text of the class in which it is declared, and when a `protected internal` instance member is accessed outside the program text of the program in which it is declared, the access shall take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place *through* an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class. Instance interface members defined with `protected` or `private protected` access cannot be accessed from a `class` or `struct` that implements that interface; these can be accessed only from derived interfaces. However, `class` and `struct` types can define overridden `protected` instance members declared in an interface it implements.

Let `B` be a base class that declares a protected instance member `M`, and let `D` be a class that derives from `B`. Within the *class_body* of `D`, access to `M` can take one of the following forms:

Expand Down Expand Up @@ -781,9 +781,9 @@ When a name in an inner scope hides a name in an outer scope, it hides all overl

Name hiding through inheritance occurs when classes or structs redeclare names that were inherited from base classes. This type of name hiding takes one of the following forms:

- A constant, field, property, event, or type introduced in a class or struct hides all base class members with the same name.
- A method introduced in a class or struct hides all non-method base class members with the same name, and all base class methods with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)).
- An indexer introduced in a class or struct hides all base class indexers with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) .
- A constant, field, property, event, or type introduced in a class, struct, or interface hides all base class members with the same name.
- A method introduced in a class, struct, or interface hides all non-method base class members with the same name, and all base class methods with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)).
- An indexer introduced in a class, struct, or interface hides all base type indexers with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) .

The rules governing operator declarations ([§15.10](classes.md#1510-operators)) make it impossible for a derived class to declare an operator with the same signature as an operator in a base class. Thus, operators never hide one another.

Expand Down Expand Up @@ -913,9 +913,9 @@ where:
`R₀` is determined as follows:

- If `x` is zero and the *namespace_or_type_name* appears within a generic method declaration ([§15.6](classes.md#156-methods)) but outside the *attributes* of its *method-header*, and if that declaration includes a type parameter ([§15.2.3](classes.md#1523-type-parameters)) with name `I`, then `R₀` refers to that type parameter.
- Otherwise, if the *namespace_or_type_name* appears within a type declaration, then for each instance type `T` ([§15.3.2](classes.md#1532-the-instance-type)), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
- Otherwise, if the *namespace_or_type_name* appears within a type declaration, then for each instance type `T` ([§15.3.2](classes.md#1532-the-instance-type)), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class, struct, or interface declaration (if any):
- If `x` is zero and the declaration of `T` includes a type parameter with name `I`, then `R₀` refers to that type parameter.
- Otherwise, if the *namespace_or_type_name* appears within the body of the type declaration, and `T` or any of its base types contain a nested accessible type having name `I` and `x` type parameters, then `R₀` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected.
- Otherwise, if the *namespace_or_type_name* appears within the body of the type declaration, and `T` or any of its base types contain a nested accessible type having name `I` and `x` type parameters, then `R₀` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. It is a compiler error if no type is more derived than all others.
> *Note*: Non-type members (constants, fields, methods, properties, indexers, operators, instance constructors, finalizers, and static constructors) and type members with a different number of type parameters are ignored when determining the meaning of the *namespace_or_type_name*. *end note*
- Otherwise, for each namespace `N`, starting with the namespace in which the *namespace_or_type_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:
- If `x` is zero and `I` is the name of a namespace in `N`, then:
Expand Down Expand Up @@ -945,7 +945,7 @@ For each repetition `n`, where `1 ≤ n ≤ k`, its resolution, `Rₙ`; which in

- If `x` is zero and `Rₚ` refers to a namespace and `Rₚ` contains a nested namespace with name `I`, then `Rₙ` refers to that nested namespace.
- Otherwise, if `Rₚ` refers to a namespace and `Rₚ` contains an accessible type having name `I` and `x` type parameters, then `Rₙ` refers to that type constructed with the given type arguments.
- Otherwise, if `Rₚ` refers to a (possibly constructed) class or struct type and `Rₚ` or any of its base classes contain a nested accessible type having name `I` and `x` type parameters, then `Rₙ` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected.
- Otherwise, if `Rₚ` refers to a (possibly constructed) class, struct, or interface type and `Rₚ` or any of its base types contain a nested accessible type having name `I` and `x` type parameters, then `Rₙ` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. It is a compiler error if no type is more derived than all others.
> *Note*: If the meaning of `T.I`, for some type `T`, is being determined as part of resolving the base class specification of `T` then the direct base class of `T` is considered to be `object` ([§15.2.4.2](classes.md#15242-base-classes)). *end note*
- Otherwise, the *namespace_or_type_name* is invalid and a compile-time error occurs.

Expand All @@ -956,6 +956,30 @@ A *namespace_or_type_name* is permitted to reference a static class ([§15.2.2.4
- The *namespace_or_type_name* is the `T` in a *namespace_or_type_name* of the form `T.I`, or
- The *namespace_or_type_name* is the `T` in a *typeof_expression* ([§12.8.18](expressions.md#12818-the-typeof-operator)) of the form `typeof(T)`

> *Example*:
>
> <!-- Example: {template:"standalone-lib-without-using", name:"MultipleNested", expectedErrors:["CS0104"]} -->
> ```csharp
> interface A
> {
> class NestedClass { public static void M() {} }
> }
>
> interface B
> {
> class NestedClass { public static void M() {} }
> }
>
> interface C : A, B
> {
> public void Test() { NestedClass.M(); } // ambiguity between A.NestedClass and B.NestedClass
> }
> ```
>
> In the example above, the call to `NestedClass.M()` in `C.Test()` is ambiguous between `B.NestedClass.M()` and `A.NestedClass.M()` because neither is more derived than the other. An explicit reference to either `A.NestedClass.M()` or `B.NestedClass.M()` is required to resolve the ambiguity.
>
> *end example*

### 7.8.2 Unqualified names

Every namespace declaration and type declaration has an ***unqualified name*** determined as follows:
Expand Down
Loading