So far, declaration of an executable’s Main method has been the simplest declaration possible. You have not included any parameters or non-void return type in your Main method declarations. However, C# supports the ability to retrieve the command-line arguments when executing a program, and it is possible to return a status indicator from the Main method.
The runtime passes the command-line arguments to Main() using a single string array parameter – names args by convention. All you need to do to retrieve the parameters is to access the array, as demonstrated in Listing 5.15 with Output 5.3. The output shows a run with no parameters and a second run with two parameters. The purpose of this program is to download a file whose location is specified by a URL. The first command-line argument identifies the URL, and the second argument is the filename to which to save the file. The listing begins with a switch statement that evaluates the number of parameters (args.Length) as follows:
If you were successful in calculating the target filename, you would use it to save the downloaded file. Otherwise, you would display the help text. The Main() method also returns an int rather than a void. This is optional for a Main method declarations, but if it is used, the program can return an exit code to a caller (such as a script or a batch file). By convention, a return other than zero indicates an error.
Although all command-line arguments can be passed to Main() via an array of strings, sometimes it is convenient to access the arguments from inside a method other than Main(). The System.Environment.GetCommandLineArgs() method returns the command-line arguments array in the same form that Main(string args) passes the arguments into the Main method except that the first item in the array is the executable file name.
To download the file, Listing 5.15 uses an System.Net.Http.HttpClient object, its namespace imported by ImplicitUsings element in the csproj file.
If a program includes two classes with Main methods, it is possible to specify which one to use as the entry point. In Visual Studio, right-clicking on the project from Solution Explorer and selecting Properties provides a user interface on top of the project file. By selecting the Application tab on the left, you can edit the Startup Object and select which type’s Main method will start the program. The result will be an additional element in the PropertyGroup:
On the command line, you can specify the same value, setting the StartupObject property when running a build. For example:
dotnet build /p:StartupObject=AddisonWesley.Program2
where AddisonWesley.Program2 is the namespace and class that contains the selected Main method. In fact, any item in the PropertyGroup section of a csproj file can be specified on the command line this way.)
As code executes, methods call more methods, which in turn call additional methods, and so on. In the simple case of Listing 5.4, Main() calls GetUserInput(), which in turn calls System.Console.ReadLine(), which in turn calls even more methods internally. Every time a new method is invoked, the runtime creates an activation frame that contains information about the arguments passed to the new call, the local variables of the new call, and information about where control should resume when the new method returns. The set of calls within calls within calls, and so on, produces a series of activation frames that is termed the call stack.5 As program complexity increases, the call stack generally gets larger and larger as each method calls another method. As calls complete, however, the call stack shrinks until another method is invoked. The process of removing activation frames from the call stack is termed stack unwinding. Stack unwinding always occurs in the reverse order of the method calls. When the method completes, execution returns to the call site—that is, the location from which the method was invoked.