47 lines
4.6 KiB
Markdown
47 lines
4.6 KiB
Markdown
# C# Language Design Notes for July 9, 2014
|
||
|
||
## Agenda
|
||
1. Detailed design of nameof <_details settled_>
|
||
2. Design of #pragma warning extensions <_allow identifiers_>
|
||
|
||
## Details of nameof
|
||
The overall design of `nameof` was decided in the design meeting on [Oct 7, 2013](https://roslyn.codeplex.com/discussions/552376). However, a number of issues weren’t addressed at the time.
|
||
|
||
### Syntactic ambiguity
|
||
The use of `nameof(…)` as an expression can be ambiguous, as it looks like an invocation. In order to stay compatible, if there’s an invokable `nameof` in scope we’ll treat it as an invocation, regardless of whether that invocation is valid. This means that in those cases there is no way to apply the nameof operator. The recommendation of course will be to get rid of any use of `nameof` as an identifier, and we should think about having diagnostics helping with that.
|
||
|
||
### Which operands are allowed?
|
||
The symbols recognized in a nameof expression must represent locals, range variables, parameters, type parameters, members, types or namespaces. Labels and preprocessor symbols are not allowed in a nameof expression.
|
||
|
||
In general, free-standing identifiers are looked up like simple names, and dotted rightmost identifiers are looked up like member access. It is thus an error to reference locals before their declaration, or to reference inaccessible members. However, there are some exceptions:
|
||
|
||
_All members are treated as if they were static members._ This means that instance members are accessed by dotting off the type rather than an instance expression. It also means that the accessibility rules around protected instance members are the simpler rules that apply to static members.
|
||
|
||
_Generic types are recognized by name only._ Normally there needs to be a type parameter list (or at least dimension specifier) to disambiguate, but type parameter lists or dimension specifiers are not needed, and in fact not allowed, on the rightmost identifier in a nameof.
|
||
|
||
_Ambiguities are not an error._ Even if multiple entities with the same name are found, nameof will succeed. For instance, if a property named `M` is inherited through one interface and a method named `M` is inherited through another, the usual ambiguity error will not occur.
|
||
|
||
### The referenced set
|
||
Because ambiguities are allowed, a nameof operator can reference a set of different entities at the same time. The precise set of referenced entities in the presence of ambiguity can be loosely defined as “those it would be ambiguous between”. Thus, shadowed members or other entities that wouldn’t normally be found by lookup, e.g. because they are in a base class or an enclosing scope of where an entity is found, will not be part of the referenced set.
|
||
|
||
The notion of referenced set has little importance for the language-level semantics, but is important for the tooling experience, e.g. for refactorings, go-to-definition, etc.
|
||
Reference to some entities, e.g. obsolete members, `Finalize` or ‘`op_`’ methods, is normally an error. However, it is not an error in `nameof(…)` unless _all_ members of the referenced set would give an error. If all non-error references give warnings, then a warning is given.
|
||
|
||
### The resulting string
|
||
C# doesn’t actually have a notion of canonical name. Instead, equality between names is currently defined directly _between_ names that may contain special symbols.
|
||
|
||
For `nameof(… i)` we want the resulting string to be the identifier `I` given, except that formatting characters are omitted, and Unicode escapes are resolved. Also, any leading `@` is removed.
|
||
|
||
In the case of aliases, this means that those are not resolved to their underlying meaning: the identifier is that of the alias itself.
|
||
|
||
As a result, the meaning of the identifier is always only used to check if it is valid, never to decide what the resulting string is. There is no semantic component to determining the result of a nameof operator, only to determining if it is allowed.
|
||
|
||
## Pragma warning directives
|
||
Now that custom diagnostics are on their way, we want to allow users to turn these on and off from source code, just as we do with the compiler’s own diagnostics today. To allow this, we need to extend the model of how a diagnostic is identified: today a number is used, but that is not a scalable model when multiple diagnostic providers are involved.
|
||
|
||
Instead the design is that diagnostics are identified by an identifier. For compatibility the C# compiler’s own diagnostics can still be referenced with a number, but can also be referred to with the pattern `CS1234`:
|
||
``` c#
|
||
#pragma warning disable AsyncCoreSet
|
||
#pragma warning disable CS1234
|
||
```
|
||
|