This chapter already used Console.WriteLine repeatedly for writing out text to the command console. In addition to being able to write out data, a program needs to be able to accept data that a user may enter.
One way to retrieve text that is entered at the console is to use Console.ReadLine(). This method stops the program execution so that the user can enter characters. When the user presses the Enter key, creating a newline, the program continues. The output, also known as the return, from the Console.ReadLine() method is the string of text that was entered. Consider Listing 1.16 and the corresponding output shown in Output 1.4.
After each prompt, this program uses the Console.ReadLine() method to retrieve the text the user entered and assign it to an appropriate variable. By the time the second Console.ReadLine() assignment completes, firstName refers to the value Inigo and lastName refers to the value Montoya.
If you encounter a CS8600, “Converting null literal or possible null value to non-nullable type,” warning when assigning Console.ReadLine(), you can safely ignore it until Chapter 2. Alternatively, use string? rather than string when declaring the firstName and lastName variables to address the warning. You can also disable the nullable-related warnings entirely by disabling them, setting the Nullable element in your project file to disable (<Nullable>disable</Nullable>) within the PropertyGroup element of the .csproj file.
In addition to the System.Console.ReadLine() method, there is a System.Console.Read() method. However, the data type returned by the System.Console.Read() method is an integer corresponding to the character value read, or –1 if no more characters are available. To retrieve the actual character, it is necessary to first cast the integer to a character, as shown in Listing 1.17.
The Console.Read() method does not return the input until the user presses the Enter key; no processing of characters will begin, even if the user types multiple characters before pressing the Enter key.
You can use Console.ReadKey(),11 which, in contrast to Console.Read(), returns the input after a single keystroke. It allows the developer to intercept the keystroke and perform actions such as key validation or to restrict the characters to numerics.
Listing 1.16 prompted the user for their first and last names using the method Console.Write() rather than Console.WriteLine(). Instead of placing a newline character after displaying the text, the Console.Write() method leaves the current position on the same line. In this way, any text the user enters will be on the same line as the prompt for input. The output from Listing 1.16 demonstrates the effect of Console.Write().
The next step is to write the values retrieved using Console.ReadLine() back to the console. In the case of Listing 1.18, the program writes out the user’s full name. However, instead of using Console.WriteLine() as before, this code uses a slight variation that leverages string interpolation.12 Notice in Listing 1.18, the dollar sign preceding the string literal in the call to Console.WriteLine; it indicates that string interpolation will be used. Output 1.5 shows the corresponding output.
Instead of writing out “Your full name is” followed by another Write statement for firstName, a third Write statement for the space, and finally a WriteLine statement for lastName, Listing 1.18 writes out the entire output string interpolation. With string interpolation, the compiler interprets the interior of the curly brackets within the string as regions in which you can embed code (expressions) that the compiler will evaluate and convert to strings. Rather than executing lots of code snippets individually and combining the results as a string at the end, string interpolation allows you to do this in a single step. This makes the code easier to understand.
Prior to C# 6.0, C# used a different approach, that of composite formatting. With composite formatting, the code first supplies a format string to define the output format—see Listing 1.19.
In this example, the format string is Your full name is {0} {1}. It identifies two indexed placeholders for data insertion in the string. Each placeholder corresponds to the order of the arguments that appear after the format string.
Note that the index value begins at zero. Each inserted argument (known as a format item) appears after the format string in the order corresponding to the index value. In this example, since firstName is the first argument to follow immediately after the format string, it corresponds to index value 0. Similarly, lastName corresponds to index value 1.
Note that the placeholders within the format string need not appear in order. For example, Listing 1.20 switches the order of the indexed placeholders and adds a comma, which changes the way the name is displayed (see Output 1.6).
In addition to not having the placeholders appear consecutively within the format string, it is possible to use the same placeholder multiple times within a format string. Furthermore, it is possible to omit a placeholder. It is not possible, however, to have placeholders that do not have a corresponding argument.
In this section, we modify the program in Listing 1.19 by adding comments. In no way does this modification change the execution of the program; rather, providing comments within the code can simply make the code more understandable in areas where it isn’t inherently clear. Listing 1.21 shows the new code, and Output 1.7 shows the corresponding output.
Despite the inserted comments, compiling and executing the new program produces the same output as before.
Programmers use comments to describe and explain the code they are writing, especially where the syntax itself is difficult to understand, or perhaps a particular algorithm implementation is surprising. Since comments are pertinent only to the programmer reviewing the code, the compiler ignores comments and generates an assembly that is devoid of any trace that comments were part of the original source code.
Table 1.2 shows four different C# comment types. The program in Listing 1.21 includes three of these.
Comment Type |
Description |
Example |
Delimited comments |
A forward slash followed by an asterisk, /*, identifies the beginning of a delimited comment. To end the comment, use an asterisk followed by a forward slash: */. Comments of this form may span multiple lines in the code file or appear embedded within a line of code. The asterisks that appear at the beginning of the lines but within the delimiters are simply for formatting. |
/*comment*/ |
Single-line comments |
Comments may be declared with a delimiter comprising two consecutive forward slash characters: //. The compiler treats all text from the delimiter to the end of the line as a comment. Comments of this form are considered a single line. It is possible, however, to place sequential single-line comments one after another, as is the case with the last comment in Listing 1.19. |
//comment |
XML delimited comments |
Comments that begin with /** and end with **/ are called XML delimited comments. They have the same characteristics as regular delimited comments, except that instead of ignoring XML comments entirely, the compiler can place them into a separate text file.13 |
/**comment**/ |
XML single-line comments |
XML single-line comments begin with /// and continue to the end of the line. In addition, the compiler can save single-line comments into a separate file with the XML delimited comments. |
///comment |
A more comprehensive discussion of the XML comments and how they are leveraged to generate API documentation appears in Chapter 10, where we further discuss the various XML tags.
There was a period in programming history when a prolific set of comments implied a disciplined and experienced programmer. This is no longer the case. Instead, code that is readable without comments is more valuable than that which requires comments to clarify what it does. If developers find it necessary to enter comments to clarify what a block of code is doing, they should favor rewriting the code more clearly over commenting it. Writing comments that simply repeat what the code clearly shows serves only to clutter the code, decrease its readability, and increase the likelihood of the comments going out of date because the code changes without the comments getting updated.
The Extensible Markup Language (XML) is a simple and flexible hierarchical text format. XML is extensible because included within an XML document is information that describes the data, known as metadata. Here is a sample XML file:
<?xml version="1.0" encoding="utf-8" ?>
<body>
<book title="Essential C# 11.0">
<chapters>
<chapter title="Introducing C#"/>
<chapter title="Data Types"/>
...
</chapters>
</book>
</body>
The file starts with a header indicating the version and character encoding of the XML file, after which appears one main “book” element. Elements begin with a word in angle brackets, such as <body>. To end an element, place the same word in angle brackets and add a forward slash to prefix the word, as in </body>. In addition to elements, XML supports attributes. title="Essential C#" is an example of an XML attribute. Note that the metadata (book title, chapter, and so on) describing the data (“Essential C#,” “Data Types”) is included in the XML file. This can result in rather bloated files, but it offers the advantage that the data includes a description to aid in interpreting it.
One significant feature of using an IDE is its support for debugging. To try it, follow these additional steps in either operating system version of Visual Studio or in Visual Studio Code:
For more information about debugging, see the links corresponding to each version:
________________________________________