-
Notifications
You must be signed in to change notification settings - Fork 6k
Cover async Main language reference #2820
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
[Inside a C# Program](../../../csharp/programming-guide/inside-a-program/index.md) | ||
[\<paveover>C# Sample Applications](http://msdn.microsoft.com/en-us/9a9d7aaa-51d3-4224-b564-95409b0f3e15) | ||
# Main() and command-line arguments (C# Programming Guide) | ||
The `Main` method is the entry point of a C# console application or windows application. (Libraries and services do not require a `Main` method as an entry point.). When the application is started, the `Main` method is the first method that is invoked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than "console application or windows application", should we just say "executable application" or something like that? Is "windows" here meant to refer to the OS or to an application that has "windows"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
## Overview | ||
|
||
- The `Main` method is the entry point of an .exe program; it is where the program control starts and ends. | ||
- `Main` is declared inside a class or struct. `Main` must be [static](../../../csharp/language-reference/keywords/static.md) and it should not be [public](../../../csharp/language-reference/keywords/public.md). (In the earlier example, it receives the default access of [private](../../../csharp/language-reference/keywords/private.md).) The enclosing class or struct is not required to be static. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and it should not be public
It doesn't need to be public, but why shouldn't it be public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Note: I looked through old versions of the C# Spec, and this was never true, and never part of the spec. I wonder how this snuck through in this content (because it has been there for quite a while)
- The `Main` method is the entry point of an .exe program; it is where the program control starts and ends. | ||
- `Main` is declared inside a class or struct. `Main` must be [static](../../../csharp/language-reference/keywords/static.md) and it should not be [public](../../../csharp/language-reference/keywords/public.md). (In the earlier example, it receives the default access of [private](../../../csharp/language-reference/keywords/private.md).) The enclosing class or struct is not required to be static. | ||
- `Main` can either have a `void`, `int`, `Task`, or `Task<int>` return type. | ||
- If and only if `Main` returns a `Task` or `Task<int>`, the declaration of `Main` may include the [`async`](../../language-reference/keywords/async.md) modifier. Note that this specifically excludes an `async void Main` method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If and only if
Technically this isn't correct (the "only if" is correct, but not the "if"). It's valid to have, e.g.
static Task Main() => Task.CompletedTask;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I take back my correctness comment. You say "may include", so that's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
|
||
!code-cs[csProgGuideMain#13](../../../csharp/programming-guide/inside-a-program/codesnippet/CSharp/main-return-values_2.cs)] | ||
|
||
If the return value from `Main` is not used, returning `void` allows for slightly simpler code. However, returning an integer enables the program to communicate status information to other programs or scripts that invoke the executable file. The following example shows how the return value from `Main` can be accessed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's be worth explicitly stating that the returned value is treated as the exit code for the process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Async Main return values move the boilerplate code necessary for calling asynchronous methods in `Main` to code generated by the compiler. Previously, you would need to write this construct to call asynchronous code and ensure your program ran until the asynchronous operation completed: | ||
|
||
```csharp | ||
public static void Main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doc earlier explicitly stated that Main shouldn't be public (and I commented on why it was making that guidance), but here it's public 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦♂️
[\<paveover>C# Sample Applications](http://msdn.microsoft.com/en-us/9a9d7aaa-51d3-4224-b564-95409b0f3e15) | ||
# Main() and command-line arguments (C# Programming Guide) | ||
|
||
The `Main` method is the entry point of a C# application. (Libraries and services do not require a `Main` method as an entry point.). When the application is started, the `Main` method is the first method that is invoked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra period in "point.)."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
- If and only if `Main` returns a `Task` or `Task<int>`, the declaration of `Main` may include the [`async`](../../language-reference/keywords/async.md) modifier. Note that this specifically excludes an `async void Main` method. | ||
- The `Main` method can be declared with or without a `string[]` parameter that contains command-line arguments. When using [!INCLUDE[vsprvs](~/includes/vsprvs-md.md)] to create Windows applications, you can add the parameter manually or else use the <xref:System.Environment> class to obtain the command-line arguments. Parameters are read as zero-indexed command-line arguments. Unlike C and C++, the name of the program is not treated as the first command-line argument. | ||
|
||
The addition of `async` and `Task`, `Task<int>` returns types is only available with C# 7.1 and higher. This feature simplifies program code when console applications need to start and `await` asyncnhronous operations in `Main`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: asyncnhronous --> asynchronous
But see comment above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
|
||
- The `Main` method is the entry point of an executable program; it is where the program control starts and ends. | ||
- `Main` is declared inside a class or struct. `Main` must be [static](../../../csharp/language-reference/keywords/static.md) and it need not be [public](../../../csharp/language-reference/keywords/public.md). (In the earlier example, it receives the default access of [private](../../../csharp/language-reference/keywords/private.md).) The enclosing class or struct is not required to be static. | ||
- `Main` can either have a `void`, `int`, `Task`, or `Task<int>` return type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd mention the C# version here, not later where it's likely to be overlooked: "Main
can either have a void
, int
, or, starting with C# 7.1, a Task
or a Task<int>
return type."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
[C# Programming Guide](../../../csharp/programming-guide/index.md) | ||
[Methods](../../../csharp/programming-guide/classes-and-structs/methods.md) | ||
[Inside a C# Program](../../../csharp/programming-guide/inside-a-program/index.md) | ||
[\<paveover>C# Sample Applications](http://msdn.microsoft.com/en-us/9a9d7aaa-51d3-4224-b564-95409b0f3e15) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
||
[!code-cs[csProgGuideMain#14](../../../csharp/programming-guide/inside-a-program/codesnippet/CSharp/main-return-values_3.cs)] | ||
|
||
When a program is executed in Windows, any value returned from the `Main` function is stored in an environment variable. This environment variable can be retrieved using `ERRORLEVEL` from a batch file, or from `$LastExitCode` from powershell. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better: "using ERRORLEVEL
from a batch file or $LastExitCode
from Powershell."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
|
||
## Compiler generated code | ||
|
||
When the application entry point does return a `Task` or `Task<int>` The compiler will generate a new entry point that will call the entry point method declared in the application code. If you imagine that this entry point is called `$GeneratedMain`, the new allowed signatures will behave as follows: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does return --> returns
comma before "The compiler", and lowercase "the"
will generate --> generates
will call --> calls
If you imagine --> Assuming
"the new allowed signatures will behave" is an awkward phrase; I'm not sure what it means.
|
||
When the application entry point does return a `Task` or `Task<int>` The compiler will generate a new entry point that will call the entry point method declared in the application code. If you imagine that this entry point is called `$GeneratedMain`, the new allowed signatures will behave as follows: | ||
|
||
- `static Task Main()` will result in the compiler emitting the equivalent of private `static void $GeneratedMain() => Main().GetAwaiter().GetResult();` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In each of these cases, it's best to use present rather than future tense.
private
should also be fenced
- `static Task<int> Main(string[])` will result in the compiler emitting the equivalent of `private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();` | ||
|
||
> [!NOTE] | ||
> The above examples could all have the `async` modifier on the `Main` method and would generate the same resulting code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somewhat clearer, perhaps: If the examples all used the async
modifier on the Main
method, the compiler would generate the same code.
Thanks @rpetrusha. I've addressed all the concerns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I didn't notice: on line 60, "returns types" --> "return types". Otherwise, LGTM, @BillWagner, and this will be ready to merge when you want.
Fixes #2795
/cc @stephentoub