Returns and Parameters on Main Method

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—named args by convention. All you need to do to retrieve the parameters is to access the array, as demonstrated in Listing 5.16 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:

1.
If there are not two parameters, display an error indicating that it is necessary to provide the URL and filename.
2.
The presence of two arguments indicates the user has provided both the URL of the resource and the download target filename.
Listing 5.16: Passing Command-Line Arguments to a Main Method
public class Program
{
    public static int Main(string[] args)
    {
        int result;
        if(args?.Length != 2 )
        {
            // Exactly two arguments must be specified; give an error
            Console.WriteLine(
                "ERROR:  You must specify the "
                + "URL and the file name");
            Console.WriteLine(
                "Usage: Downloader.exe <URL> <TargetFileName>");
            result = 1;
        }
        else
        {
            string urlString = args[0];
            string fileName = args[1];
            HttpClient client = new();
            byte[] response =
                client.GetByteArrayAsync(urlString).Result;
            client.Dispose();
            File.WriteAllBytes(fileName, response);
            Console.WriteLine($"Downloaded '{ fileName }' from '{ urlString }'.");
            result = 0;
        }
        return result;
    }
}
Output 5.3
>Downloader
ERROR:  You must specify the URL and the file name
Usage: Downloader.exe <URL> <TargetFileName>
>Downloader https://IntelliTect.com Index.html
Downloaded ‘Index.html’ from ‘https://IntelliTect.com’.

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 filename.

To download the file, Listing 5.16 uses a System.Net.Http.HttpClient object but only specified HttpClient—its namespace is imported by the ImplicitUsings element in the .csproj file.

AdVanced Topic
Disambiguate Multiple Main Methods

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:

<StartupObject>AddisonWesley.Michaelis.EssentialCSharp.

Shared.Program

</StartupObject>

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.)

Beginner Topic
Call Stack and Call Site

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.

________________________________________

5. Except for async or iterator methods, which move their activator records onto the heap.
{{ snackbarMessage }}