Skip to content
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

C# Programming guide: Top-level statements #23234

Merged
merged 15 commits into from
Mar 11, 2021
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "-main (C# Compiler Options)"
title: "-main (C# Compiler Options)"
ms.date: 07/20/2015
ms.date: 03/08/2021
f1_keywords:
- "/main"
helpviewer_keywords:
Expand Down Expand Up @@ -32,6 +32,9 @@ If your compilation includes more than one type with a [Main](../../programming-

This option is for use when compiling an *.exe* file.

> [!NOTE]
> This option can't be used for a project that includes [top-level statements](../../programming-guide/main-and-command-args/top-level-statements.md), even if that project contains one or more `Main` methods.

### To set this compiler option in the Visual Studio development environment

1. Open the project's **Properties** page.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
---
title: "Methods - C# Programming Guide"
description: A method in C# is a code block that contains a series of statements. A program runs the statements by calling the method and specifying arguments.
ms.date: 07/20/2015
ms.date: 03/08/2021
helpviewer_keywords:
- "methods [C#]"
- "C# language, methods"
ms.assetid: cc738f07-e8cd-4683-9585-9f40c0667c37
---
# Methods (C# Programming Guide)

A method is a code block that contains a series of statements. A program causes the statements to be executed by calling the method and specifying any required method arguments. In C#, every executed instruction is performed in the context of a method. The `Main` method is the entry point for every C# application and it's called by the common language runtime (CLR) when the program is started.
A method is a code block that contains a series of statements. A program causes the statements to be executed by calling the method and specifying any required method arguments. In C#, every executed instruction is performed in the context of a method.

The `Main` method is the entry point for every C# application and it's called by the common language runtime (CLR) when the program is started. In an application that uses [top-level statements](../main-and-command-args/top-level-statements.md), the `Main` method is implicit.
tdykstra marked this conversation as resolved.
Show resolved Hide resolved

> [!NOTE]
> This article discusses named methods. For information about anonymous functions, see [Anonymous Functions](../statements-expressions-operators/anonymous-functions.md).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: "How to display command-line arguments - C# Programming Guide"
description: Learn how to display command-line arguments. See a code example and view additional available resources.
ms.date: 07/20/2015
ms.date: 03/08/2021
helpviewer_keywords:
- "command-line arguments [C#], displaying"
ms.assetid: b8479f2d-9e05-4d38-82da-2e61246e5437
---
# How to display command-line arguments (C# Programming Guide)

Arguments provided to an executable on the command line are accessible through an optional parameter to `Main`. The arguments are provided in the form of an array of strings. Each element of the array contains one argument. White-space between arguments is removed. For example, consider these command-line invocations of a fictitious executable:
Arguments provided to an executable on the command line are accessible in [top-level statements](top-level-statements.md) and through an optional parameter to `Main`. The arguments are provided in the form of an array of strings. Each element of the array contains one argument. White-space between arguments is removed. For example, consider these command-line invocations of a fictitious executable:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is "and" extra?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was intentional, as these are two different options -- top-level statements (implicit Main) and explicit Main. But I'll change "and" to "or" as that may be clearer.


|Input on command line|Array of strings passed to Main|
|----------------------------|-------------------------------------|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Main() and command-line arguments - C# Programming Guide"
description: Learn about Main() and command-line arguments. The 'Main' method is the entry point of an executable program.
ms.date: 08/02/2017
ms.date: 03/08/2021
f1_keywords:
- "main_CSharpKeyword"
- "Main"
Expand All @@ -21,6 +21,12 @@ There can only be one entry point in a C# program. If you have more than one cla

[!code-csharp[csProgGuideMain#17](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideMain/CS/Class1.cs#17)]

Starting in C# 9, you can omit the `Main` method, and write C# statements as if they were in the `Main` method, as in the following example:

:::code language="csharp" source="snippets/top-level-statements-1/Program.cs":::

For information about how to write application code without a `Main` method, see [Top-level statements](top-level-statements.md).
tdykstra marked this conversation as resolved.
Show resolved Hide resolved

## Overview

- The `Main` method is the entry point of an executable program; it is where the program control starts and ends.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ It can also return an `int`:

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 return value from `Main` is treated as the exit code for the process. If `void` is returned from `Main`, the exit code will be implicitly `0`. The following example shows how the return value from `Main` can be accessed.

An application that uses [top-level statements](top-level-statements.md) can also return an exit code. For more information, see [Top-level statements (C# Programming Guide)](top-level-statements.md#the-application-can-return-an-int).

## Example

This example uses [.NET Core](../../../core/introduction.md) command-line tools. If you are unfamiliar with .NET Core command-line tools, you can learn about them in this [get-started article](../../../core/tutorials/with-visual-studio-code.md).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System;

Console.WriteLine("Hello World!");
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

</Project>
tdykstra marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

MyClass.TestMethod();
MyNamespace.MyClass.MyMethod();

public class MyClass
{
public static void TestMethod()
{
Console.WriteLine("Hello World!");
}

}

namespace MyNamespace
{
class MyClass
{
public static void MyMethod()
{
Console.WriteLine("Hello World from MyNamespace.MyClass.MyMethod!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

if (args.Length > 0)
{
foreach (var arg in args)
{
Console.WriteLine($"Argument={arg}");
}
}
else
{
Console.WriteLine("No arguments");
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
tdykstra marked this conversation as resolved.
Show resolved Hide resolved

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System;
using System.Threading.Tasks;

Console.Write("Hello ");
await Task.Delay(5000);
Console.WriteLine("World!");
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using System;

int returnValue = int.Parse(Console.ReadLine());
return returnValue;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
title: "Top-level statements - C# Programming Guide"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature is also known as "simple programs" if I recall correctly. You may want to include this name for SEO purposes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did you see this name?

Copy link
Member

@Youssef1313 Youssef1313 Mar 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public messaging has been consistently to call this feature "top-level statements," and with "simple programs" showing up only in the Roslyn repo, I think using that as an alternate feature name would be unnecessarily confusing, but I'll follow the lead of the top-level statements tutorial and work in the phrase "simple programs" into the text.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Top level statements" is the official name. The product team followed our lead here to avoid the use of "simple". The goal is that programs that use "top level statements" need not be "simple". See FeatherApp for one example of possibilities.

description: Learn about top-level statements in C# 9 and later.
ms.date: 03/08/2021
helpviewer_keywords:
- "C# language, top-level statements"
- "C# language, Main method"
---
# Top-level statements (C# Programming Guide)

Starting in C# 9, you don't have to explicitly include a `Main` method in a console application project. Instead, you can use the *top-level statements* feature to minimize the code you have to write. In this case, the compiler provides an implicit class and `Main` method entry point for the application.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally lean towards using main without backticks instead of Main. Because the method the compiler generates isn't called Main, but <Main>$.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "implicit" clarifies the status of Main, but in this instance it will be clearer to repeat "implicit" directly before Main.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think "implicit" resolves this. It could be implicit and called Main, but the compiler implementation decided it's called <Main>$.

And actually, from a compiler-point of view, it's not implicit at all (see discussion at dotnet/roslyn#48199), but it's okay to mention implicit for the purpose of this article I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned in the other thread, I'll add an explanation that the actual generated name is an implementation detail.


Here's a *Program.cs* file that is a complete C# program in C# 9:

:::code language="csharp" source="snippets/top-level-statements-1/Program.cs":::

Top-level statements simplify the code for small utilities such as Azure Functions and GitHub Actions. They also make it simpler for new C# programmers to get started learning and writing code.

## Rules for top-level statements.

The following sections explain the rules on what you can and can't do with top-level statements.

### Only one file can have top-level statements

An application must have only one entry point, so a project can have only one file with top-level statements. Putting top-level statements in more than one file in a project results in the following compiler error:

> CS8802 Only one compilation unit can have top-level statements.

### No other entry points

You can write a `Main` method explicitly, but it can't function as an entry point. The compiler issues the following warning:

> CS7022 The entry point of the program is global code; ignoring 'Main()' entry point.

In a project with top-level statements, you can't use the [-main](../../language-reference/compiler-options/main-compiler-option.md) compiler option to select the application's entry point.

### `using` directives are allowed

If you include using directives, they must come first in the file, as in this example:

:::code language="csharp" source="snippets/top-level-statements-1/Program.cs":::

### Global namespace

Top-level statements are implicitly in the global namespace. A class and a `Main` method are implicitly generated, but there is no implicitly generated namespace.

### Namespaces and type definitions are allowed

A file with top-level statements can also contain namespaces and type definitions, but they must come after the top-level statements. Here's an example:

:::code language="csharp" source="snippets/top-level-statements-2/Program.cs":::

### `args` is available.

Top-level statements can reference the args variable, which contains any command-line arguments that were entered. The `args` variable is never null but has `Length` 0 if no command-line arguments were provided.

:::code language="csharp" source="snippets/top-level-statements-3/Program.cs":::

### `await` is available

You can call an async method by using `await`. For example:

:::code language="csharp" source="snippets/top-level-statements-4/Program.cs":::

### The application can return an `int`

To return an `int` value when the application ends, use the `return` statement as you would in a `Main` method that returns an `int`. For example:

:::code language="csharp" source="snippets/top-level-statements-4/Program.cs":::

## Implicit `Main` method signature

The compiler generates an implicit `Main` method with a signature that depends on what code is found within the top-level statements.

| Top-level code contains| Implicit `Main` signature |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this table. See my previous comment about the return value of Main. Adding this table there would be perfect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a slightly modified table to both the return value and command-line args docs.

|------------------------|----------------------------------------------|
| `await` and `return` | `static async Task<int> Main(string[] args)` |
tdykstra marked this conversation as resolved.
Show resolved Hide resolved
| `await` | `static async Task Main(string[] args)` |
| `return` | `static int Main(string[] args)` |
| No `await` or `return` | `static void Main(string[] args)` |
tdykstra marked this conversation as resolved.
Show resolved Hide resolved

## C# language specification

[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a link to the top level statements speclet. The link would be ~/_csharplang/proposals/csharp-9.0/top-level-statements.md

## See also

- [C# Programming Guide](../index.md)
- [Methods](../classes-and-structs/methods.md)
- [Inside a C# Program](../inside-a-program/index.md)
8 changes: 4 additions & 4 deletions docs/csharp/tutorials/exploration/top-level-statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ using System;
Console.WriteLine("Hello World!");
```

This action simplifies what's needed to begin exploring new ideas. You can use top-level statements for scripting scenarios, or to explore. Once you've got the basics working, you can start refactoring the code and create methods, classes, or other assemblies for reusable components you've built. Top-level statements do enable quick experimentation and beginner tutorials. They also provide a smooth path from experimentation to full programs.
This feature simplifies what's needed to begin exploring new ideas. You can use top-level statements for scripting scenarios, or to explore. Once you've got the basics working, you can start refactoring the code and create methods, classes, or other assemblies for reusable components you've built. Top-level statements do enable quick experimentation and beginner tutorials. They also provide a smooth path from experimentation to full programs.

Top-level statements are executed in the order they appear in the file. Top-level statements can only be used in one source file in your application. The compiler generates an error if you use them in more than one file.

Expand Down Expand Up @@ -150,7 +150,7 @@ Console.WriteLine();

string[] answers =
{
"It is certain.", "Reply hazy, try again.", "Dont count on it.",
"It is certain.", "Reply hazy, try again.", "Don't count on it.",
"It is decidedly so.", "Ask again later.", "My reply is no.",
"Without a doubt.", "Better not tell you now.", "My sources say no.",
"Yes – definitely.", "Cannot predict now.", "Outlook not so good.",
Expand Down Expand Up @@ -200,7 +200,7 @@ The preceding code creates a local function inside your main method. That's stil

:::code language="csharp" source="snippets/top-level-statements/UtilitiesPassOne.cs" ID="SnippetUtilities":::

Top-level statements can only be in one file, and that file cannot contain namespaces or types.
Top-level statements can only be in one file, and that file can also contain namespaces and types at the end of the file, after the top-level statements. But for this tutorial you put the animation method in a separate file to make it more readily reusable.

Finally, you can clean the animation code to remove some duplication:

Expand All @@ -216,4 +216,4 @@ This adds the call to `Utilities.ShowConsoleAnimation`, and adds an additional `

Top-level statements make it easier to create simple programs for use to explore new algorithms. You can experiment with algorithms by trying different snippets of code. Once you've learned what works, you can refactor the code to be more maintainable.

Top-level statements simplify programs that are based on console applications. These include Azure functions, GitHub actions, and other small utilities.
Top-level statements simplify programs that are based on console applications. These include Azure functions, GitHub actions, and other small utilities. For more information, see [Top-level statements (C# Programming Guide)](../../programming-guide/main-and-command-args/top-level-statements.md).