Team LiB
Previous Section Next Section

Developing Command Line–Driven Applications

We occasionally have a need to develop a command line–driven application— i.e., an application that doesn't have a formal GUI front-end for either soliciting input from the user or for displaying output to the user. When building such applications, we need to be able to

Reading Command-Line Arguments

As mentioned earlier, the Main method can accept command-line arguments. Such arguments are typically used to either pass in small amounts of data, or to control some aspect of the program's execution.

Command-line arguments are included as part of the command to execute a C# application, following the name of the driver class on the command line. For example, if we wanted to provide an executable named SimpleProgram.exe with the command-line arguments Jackson, ABC, and 123, we would type the following command to run the program:

SimpleProgram Jackson ABC 123

Such data gets passed to the Main method of the C# program as a string array called args (or whatever else we wish to name it, as indicated by the Main method's parameter list). To accept command-line arguments, therefore, a program must use one of the two forms of the Main method that takes a string array as a parameter:

static void Main(string[] args)
static int Main(string[] args)

The args array is automatically sized to hold however many arguments are provided on the command line when the program is invoked. In the SimpleProgram invocation at the beginning of this section, the args array would contain three entries: the string "Jackson" would be placed as the zeroeth element of the args array, the string "ABC" would be the next element of args, and the string "123" would be the last element.

Inside the Main method, we can do with args whatever we'd do with any other array; for example, determine its length, manipulate individual string items within the array, and so forth. The program that follows illustrates some of the things that we might wish to do with command-line arguments:

// FruitExample.cs

// This nonsensical program is intended to illustrate command line argument
// passing.

using System;

public class FruitExample {
  // The signature of the Main method can declare as an
  // argument a string array named 'args'. (We can name the
  // array whatever we'd like, but 'args' is the standard
  // name that most people use.)
  //
  // This array is automatically initialized when the program is run
  // from the command prompt with whatever (space-separated)
  // values ('arguments') we've typed on the command line
  // after the program name.
  //
  // For example, if this compiled program is run from the
  // command prompt as follows:
  //
  //     FruitExample apple banana cherry
  //
  // then the args array will be automatically initialized with
  // three string objects "apple", "banana", and "cherry" which
  // will be stored in array elements args[0], args[1], and
  // args[2], respectively.

  static void Main(string[] args) {
    // Let's print out a few things.
    Console.WriteLine("The args array contains " + args.Length +
                      " entries." );
    // Only execute this next block of code if the array isn't empty.
    // The Length property returns the number of elements in the array.
    if (args.Length > 0) {
      int last = args.Length - 1;
      Console.WriteLine("The last array entry is: " + args[last]);
      // Every string has a Length property, as well, that contains
      // the number of characters in the string.
      Console.WriteLine("The last array entry is " + args[last].Length +
                        " characters long.");
    }
    else {
      Console.WriteLine("No command line arguments detected");
    }
  }
}

When this program is run from the command line as follows:

FruitExample apple banana cherry

it produces the following output:

The args array contains 3 entries.
The last array entry is: cherry
The last array entry is 6 characters long.

Command-Line Arguments As Control Flags

In addition to passing data in via the command line, command-line arguments are also a convenient way to control a program's operation through the use of control flags. In the following example, valid ways to invoke the FlagExample program would be as follows:

FlagExample -b
FlagExample -f

whereas failure to provide a command-line control flag, or providing an invalid flag, causes appropriate error messages to be printed (please refer to in-line comments):

using System;

public class FlagExample
{
  static void Main(string[] args) {
    // If the user hasn't provided a control flag, report an error.
    if (args.Length != 1) {
      Console.WriteLine("Usage: FlagExample -x where x may be f or b");
    }
    else {
      if (args[0] == "-f") {
        Console.WriteLine("FOO!");
      }
      else if (args[0] == "-b") {
        Console.WriteLine("BAR ...");
      }
      else {
        Console.WriteLine("Incorrect control flag: " + args[0]);
      }
    }
  }
}

Invoking the program properly as follows:

FlagExample -f

would produce as output

  FOO!

because –f is a "legal" command-line flag, whereas invoking the program without providing a flag, as follows:

FlagExample

would produce as output

Usage:  FlagExample -x   where x may be f or b

Providing an invalid flag as follows:

FlagExample -a

would produce as output

Incorrect control flag:  -a

Accepting Keyboard Input

Most applications receive information either directly from users via an application's graphical user interface, or by reading information from a file or database. But, until you've learned how to program such things in C# in Chapters 15 and 16, it's handy to know how to prompt for textual input from the command-line window.

To read keyboard input, we'll turn once again to the Console class from the System namespace. The Console class declares a ReadLine method that can be used to read keyboard input.

public static string ReadLine()

Data is read character by character but is buffered internally by this method until the Enter key is pressed, at which point an entire line of input is returned by the method as a string.

The ReadLine method reads data from the standard input I/O stream, which in most cases is associated with the keyboard. The ReadLine method can generate an IOException, so calls to the method should be enclosed in a try block.

Here is a simple example that illustrates reading data from the keyboard using the ReadLine method; we'll present the program in its entirety first, then will narrate it in step-by-step fashion.

using System;
using System.IO;

public class KeyboardDemo
{
  static void Main() {
    string name = "";

    try {
      // Prompt the user for input; note the use of
      // Write() vs. WriteLine(), so that the prompt will
      // be displayed on the same line as the text entered
      // by the user.
      Console.Write("Enter your name: ");

      // Read their response from the keyboard.
      name = Console.ReadLine();
    }
    catch (IOException ioe) {
      Console.WriteLine("IO Exception occurred: " + ioe);
    }

    // Display the input back as a test.
    Console.WriteLine("Name entered was " + name);
  }
}

Stepping through the code:

  • When the KeyboardDemo program is run, the user is prompted to enter his or her name via a call to the Console.Write method:

          Console.Write("Enter your name: ");
    

    Note our use of Write vs. WriteLine, so that the prompt will be displayed on the same line as the text entered by the user.

  • The value of a local string variable called name is set to the string value returned by the ReadLine method:

          name = Console.ReadLine();
    

    This operation is performed inside a try block.

  • A catch clause is provided to catch IOExceptions. In a real-life application, we might want to provide a more extensive response to the exception, but in this simple example we just print out a message that an exception has occurred. The IOException class is from the System.IO namespace, so the appropriate using directive is placed at the top of the code.

Running this program would produce the following results (bolded text reflects input by the user):

Enter your name: Jackie Chan
Name entered was Jackie Chan

Printing to the Screen, Revisited

As we saw in Chapter 1, we invoke one of two methods—Console.WriteLine() or Console.Write()—to print text messages to the command-line window as follows:

Console.WriteLine(expression to be printed);
Console.Write(expression to be printed);

We glossed over the syntax of this particular operation when this capability was first introduced; now that we know much more about objects, let's revisit this syntax in more depth.

Console is a class provided by the CLR Base Class Library (part of the Framework Class Library) within the System namespace. The Console class defines numerous overloaded static Write and WriteLine methods; the various versions each accept a different argument type—string, the various predefined value types, or arbitrary object references:

public static void WriteLine(string s)
public static void WriteLine(int i)
public static void WriteLine(double d)
public static void WriteLine(bool b)
public static void WriteLine(object obj)

and so forth (the same is true for Write).

The Write and WriteLine methods can accept expressions of arbitrary complexity, and do their best to ultimately render these into a single string value, which then gets displayed to the standard output window—i.e., the command-line window from which we invoked the program. This is accomplished by calling the ToString method "behind the scenes" on nonstring arguments to render a string representation of the argument, as discussed earlier in this chapter.

The following code snippet illustrates several complex invocations of Console.Write. The expression being passed in as an argument to the first call to Write ultimately evaluates to a string value, and the expression being passed in as an argument to the second call to Write evaluates to a double value; thus, two different (overloaded) versions of the Write method are being called in this example:

Professor p = new Professor();
// Details omitted.
Console.Write("Professor " + p.Name + " has an advisee named " +
               p.Advisee.Name + " with a GPA of ");
Console.Write(p.Advisee.ComputeGPA());
Console.WriteLine("");

Here's some simulated output:

Professor Jacquie Barker has an advisee named Sandy Tucker with a GPA of 4.0.

Team LiB
Previous Section Next Section