markdown lint for C# 7.1 proposals

These had two sets of changes:

1. use `csharp` as the language identifier for code fences.
1. use relative links to other articles in the dotnet/csharplang repo that are being published on docs.microsoft.com so those links resolve to the article published there from that site.
This commit is contained in:
Bill Wagner 2019-03-07 11:50:08 -05:00
parent 0298b8676f
commit 74f60810a3
3 changed files with 21 additions and 10 deletions

View file

@ -17,7 +17,8 @@ It is very common when learning C#, when writing console-based utilities, and wh
to call and `await` `async` methods from Main. Today we add a level of complexity here by forcing such `await`'ing to be
done in a separate async method, which causes developers to need to write boilerplate like the following just to get
started:
```C#
```csharp
public static void Main()
{
MainAsync().GetAwaiter().GetResult();
@ -28,6 +29,7 @@ private static async Task MainAsync()
... // Main body here
}
```
We can remove the need for this boilerplate and make it easier to get started simply by allowing Main itself to be
`async` such that `await`s can be used in it.
@ -35,7 +37,8 @@ We can remove the need for this boilerplate and make it easier to get started si
[design]: #detailed-design
The following signatures are currently allowed entrypoints:
```C#
```csharp
static void Main()
static void Main(string[])
static int Main()
@ -43,12 +46,14 @@ static int Main(string[])
```
We extend the list of allowed entrypoints to include:
```
```csharp
static Task Main()
static Task<int> Main()
static Task Main(string[])
static Task<int> Main(string[])
```
To avoid compatibility risks, these new signatures will only be considered as valid entrypoints if no overloads of the previous set are present.
The language / compiler will not require that the entrypoint be marked as `async`, though we expect the vast majority of uses will be marked as such.
@ -59,7 +64,8 @@ When one of these is identified as the entrypoint, the compiler will synthesize
- ```static Task<int> Main(string[])``` will result in the compiler emitting the equivalent of ```private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();```
Example usage:
```C#
```csharp
using System;
using System.Net.Http;
@ -81,14 +87,17 @@ The main drawback is simply the additional complexity of supporting additional e
Other variants considered:
Allowing `async void`. We need to keep the semantics the same for code calling it directly, which would then make it difficult for a generated entrypoint to call it (no Task returned). We could solve this by generating two other methods, e.g.
```C#
```csharp
public static async void Main()
{
... // await code
}
```
becomes
```C#
```csharp
public static async void Main() => await $MainTask();
private static void $EntrypointMain() => Main().GetAwaiter().GetResult();
@ -98,6 +107,7 @@ private static async Task $MainTask()
... // await code
}
```
There are also concerns around encouraging usage of `async void`.
Using "MainAsync" instead of "Main" as the name. While the async suffix is recommended for Task-returning methods, that's primarily about library functionality, which Main is not, and supporting additional entrypoint names beyond "Main" is not worth it.

View file

@ -8,7 +8,7 @@
## Summary
[summary]: #summary
The specification for the [existing C# as operator](https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#the-as-operator) permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the `Type identifier` pattern requires there be a conversion between the type of the input and the given type.
The specification for the [existing C# as operator](../../spec/expressions.md#the-as-operator) permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the `Type identifier` pattern requires there be a conversion between the type of the input and the given type.
We propose to relax this and change `expression is Type identifier`, in addition to being permitted in the conditions when it is permitted in C# 7, to also be permitted when `expression as Type` would be allowed. Specifically, the new cases are cases where the type of the expression or the specified type is an open type.

View file

@ -9,7 +9,7 @@ This parallels the behavior of anonymous types, which allow inferring member na
This is particularly handy when using tuples in LINQ:
```
```csharp
// "c" and "result" have element names "f1" and "f2"
var result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1);
```
@ -30,7 +30,8 @@ There are two parts to the change:
Note that the rule for handling duplicates is different than that for anonymous types. For instance, `new { x.f1, x.f1 }` produces an error, but `(x.f1, x.f1)` would still be allowed (just without any inferred names). This avoids breaking existing tuple code.
For consistency, the same would apply to tuples produced by deconstruction-assignments (in C#):
```C#
```csharp
// tuple has element names "f1" and "f2"
var tuple = ((x.f1, x?.f2) = (1, 2));
```
@ -44,7 +45,7 @@ When using the C# 7.1 compiler (or later) with language version "7.0", the eleme
The main drawback is that this introduces a compatibility break from C# 7.0:
```C#
```csharp
Action y = () => M();
var t = (x: x, y);
t.y(); // this might have previously picked up an extension method called “y”, but would now call the lambda.