Replace weird quote character with regular single quote
This commit is contained in:
parent
100848e02c
commit
7c69baba8f
|
@ -15,27 +15,27 @@ Allow locals and parameters to be annotated as readonly in order to prevent shal
|
|||
|
||||
Today, the `readonly` keyword can be applied to fields; this has the effect of ensuring that a field can only
|
||||
be written to during construction (static construction in the case of a static field, or instance construction in the case of an instance field),
|
||||
which helps developers avoid mistakes by accidentally overwriting state which should not be modified. But fields aren’t the only places developers
|
||||
want to ensure that values aren’t mutated. In particular, it’s common to create a local variable to store temporary state, and accidentally updating
|
||||
which helps developers avoid mistakes by accidentally overwriting state which should not be modified. But fields aren't the only places developers
|
||||
want to ensure that values aren't mutated. In particular, it's common to create a local variable to store temporary state, and accidentally updating
|
||||
that temporary state can result in erroneous calculations and other such bugs, especially when such "locals" are captured in lambdas, at which point
|
||||
they are lifted to fields, but there's no way today to mark such lifted fields as 'readonly`.
|
||||
|
||||
## Detailed design
|
||||
[design]: #detailed-design
|
||||
|
||||
Locals will be annotatable as `readonly` as well, with the compiler ensuring that they’re only set at the time of declaration (certain locals in C# are
|
||||
already implicitly readonly, such as the iteration variable in a ‘foreach’ loop or the used variable in a ‘using’ block, but currently a developer has
|
||||
Locals will be annotatable as `readonly` as well, with the compiler ensuring that they're only set at the time of declaration (certain locals in C# are
|
||||
already implicitly readonly, such as the iteration variable in a 'foreach' loop or the used variable in a 'using' block, but currently a developer has
|
||||
no ability to mark other locals as `readonly`). Such `readonly` locals must have an initializer:
|
||||
``` C#
|
||||
readonly long maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10;
|
||||
...
|
||||
maxBytesToDelete = 0; // Error: can’t assign to readonly locals outside of declaration
|
||||
maxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration
|
||||
```
|
||||
And as shorthand for `readonly var`, the existing contextual keyword `let` may be used, e.g.
|
||||
```C#
|
||||
let maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10;
|
||||
...
|
||||
maxBytesToDelete = 0; // Error: can’t assign to readonly locals outside of declaration
|
||||
maxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration
|
||||
```
|
||||
There are no special constraints for what the initializer can be, and can be anything currently valid as an initializer for locals, e.g.
|
||||
```C#
|
||||
|
@ -43,27 +43,27 @@ readonly T data = arg1 ?? arg2;
|
|||
```
|
||||
|
||||
`readonly` on locals is particularly valuable when working with lambdas and closures. When an anonymous method or lambda accesses local state from the enclosing scope,
|
||||
that state is captured into a closure by the compiler, which is represented by a “display class.” Each “local” that’s captured is a field in this class, yet
|
||||
that state is captured into a closure by the compiler, which is represented by a 'display class.' Each 'local' that's captured is a field in this class, yet
|
||||
because the compiler is generating this field on your behalf, you have no opportunity to annotate it as `readonly` in order to prevent the lambda from erroneously
|
||||
writing to the “local” (in quotes because it’s really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda
|
||||
writing to the 'local' (in quotes because it's really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda
|
||||
from writing to local, which is particularly valuable in scenarios involving multithreading where an erroneous write could result in a dangerous but rare and
|
||||
hard-to-find concurrency bug.
|
||||
``` C#
|
||||
readonly long index = ...;
|
||||
Parallel.ForEach(data, item => {
|
||||
T element = item[index];
|
||||
index = 0; // Error: can’t assign to readonly locals outside of declaration
|
||||
index = 0; // Error: can't assign to readonly locals outside of declaration
|
||||
});
|
||||
```
|
||||
|
||||
As a special form of local, parameters will also be annotatable as `readonly`. This would have no effect on what the caller of the method is able to pass to the
|
||||
parameter (just as there’s no constraint on what values may be stored into a `readonly` field), but as with any `readonly` local, the compiler would prohibit code
|
||||
parameter (just as there's no constraint on what values may be stored into a `readonly` field), but as with any `readonly` local, the compiler would prohibit code
|
||||
from writing to the parameter after declaration, which means the body of the method is prohibited from writing to the parameter.
|
||||
``` C#
|
||||
public void Update(readonly int index = 0) // Default values are ok though not required
|
||||
{
|
||||
...
|
||||
index = 0; // Error: can’t assign to readonly parameters
|
||||
index = 0; // Error: can't assign to readonly parameters
|
||||
...
|
||||
}
|
||||
```
|
||||
|
|
Loading…
Reference in a new issue