This is a placeholder for where the essentialcsharp.com would normally lie in a production environment. Don't worry, the site is not broken 😃
-
-
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/01.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/01.html
new file mode 100644
index 00000000..626d6a3b
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/01.html
@@ -0,0 +1,1822 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1
+
+
+
+
Introducing C#
+
+
+
+
+
+The C# programming language can be used to build software components and applications that run on a wide variety of operating systems (platforms)—including mobile devices, game consoles, web applications, Internet of Things (IoT), microservices, and desktop applications. Furthermore, C# is free; in fact, it is entirely open source, so you can view, modify, redistribute, and contribute back any improvements you make. As a language, C# is built on features found in its predecessor C-style languages (C, C++, and Java), making it immediately familiar to many experienced programmers.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+This chapter introduces C# using the traditional HelloWorld program. It focuses on C# syntax fundamentals, including defining an entry point into the C# program, which will familiarize you with the C# syntax style and structure and enable you to produce the simplest of C# programs. Prior to the discussion of C# syntax fundamentals is a summary of managed execution context, which explains how a C# program executes at runtime. This chapter ends with a discussion of variable declaration, writing and retrieving data from the console, and the basics of commenting code in C#.
+
+
+
+Hello, World
+
+
+
+
+
+The best way to learn a new programming language is to write code. The first example is the classic HelloWorld program. In this program, you will display some text to the screen.
+
+
+
+Listing 1.1 shows the complete HelloWorld program; in the following sections, you will compile and run the code.
+
+
+
+
+
+Listing1.1: HelloWorld in C#2
+
+
+
+ 1.
+Console.WriteLine("Hello. My name is Inigo Montoya.");
+
+
+
+
+
+
+(A listing this simple requires a feature—top-level statements—enabled in C# 9.0 to help with learning C#. An alternative listing—arguably a more typical listing—is shown later in Listing 1.6. See Chapter 4 for more information about top-level statements.)
+
+
+
+
+
+
Beginner Topic
+
Basic Compilation Terms
+
+
+
+
+
+A compiler acts like a translator, changing code from one language to another. Generally, the compiler is responsible for converting from a higher level language, like C#, to a lower level language that a computer understands directly. In the case of C#, the compiler output is an intermediate language that a second compiler translates to machine language. This is discussed further in the “Managed Execution and the Common Language Infrastructure” section later in this chapter. Source code is simply the text that makes up a program, so Listing1.1 is considered source code to our HelloWorld Program. The word code is often used interchangeably with source code.
+Once you have written your C# code, it is time to compile and run it. Based on your operating system, you have a choice of which compiler to download. Generally, the implementation is packaged into a software development kit(SDK). The SDK includes the compiler, the runtime execution engine, the framework of pragmatically accessible functionality that the runtime can access (see “Application Programming Interface” later in the chapter), and any added tooling (such as a build engine for automating build steps) that might be bundled with the SDK. Given that there are compilers available for multiple platforms and that C# has been publicly available since 2000 (see “Multiple .NET Frameworks” later in the chapter), there are several options to choose from.
+
+
+
+For each operating system the installation instructions vary. For this reason, we recommend you visit https://dotnet.microsoft.com/download for download and installation instructions, selecting the package to download based on which operating system you will be developing on. Furthermore, you have a choice of which .NET implementation(s) to use—sometimes referred to as the .NET framework(s). While we could provide further details here, the .NET download site has the most updated instructions for each combination supported. While there are multiple framework versions available, the easiest is to download the default one, which corresponds to the latest fully released version.
+
+
+
+There are also numerous ways to edit your source code, including the most rudimentary of tools, such as Notepad on Windows, TextEdit on Mac/macOS, or vi on Linux. However, you’re likely to want something more advanced so that at least your code is colorized. Any programming editor that supports C# will suffice. If developing on Linux, we recommend you consider the open source editor Visual Studio Code (https://code.visualstudio.com). To optimize working with C# in Visual Studio Code, you will want to install the C# extension, as shown in Figure 1.1. However, if you are working on Windows or Mac, consider the corresponding version of Microsoft Visual Studio 2022 (or later)—see https://visualstudio.microsoft.com/. All are available free of charge.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Figure 1.1: Installing the C# extension for Visual Studio Code
+
+
+
+
+
+
+
+
+In the remainder of this section, we provide instructions for these editors. For Visual Studio Code, we rely on the command-line interface (CLI) tool dotnet CLI for creating the initial C# program in addition to compiling and running the program. For Windows and Mac, we focus on using the platform-specific version of Visual Studio 2022.
+
+
+
+
+
+With Dotnet CLI
+
+
+
+
+
+The dotnet command, dotnet, is the dotnet command-line interface, or dotnet CLI, and it may be used to generate the initial code base for a C# program in addition to compiling and running the program.3 (To avoid ambiguity between CLI referring to the Common Language Infrastructure or the command-line interface, throughout the book we will prefix CLI with dotnet when referring to the dotnet CLI. CLI without the dotnet prefix refers to Common Language Infrastructure.) Once you have completed the installation, verify that dotnet is an available command from the terminal—thus verifying your installation.
+
+
+
+Following are the instructions for creating, compiling, and executing the HelloWorld program from a terminal on Windows, macOS, or Linux:
+
+
+
+ 1.
+
+
+
+Open the terminal. (Optionally, consider using the cross-platform command-line interface PowerShell by running the command pwsh.4)
+
+
+
+
+
+
+
+ 2.
+
+
+
+Create a new directory where you want to place the code. Consider a name such as HelloWorld or EssentialCSharp/HelloWorld. From the command line, use
+
+
+mkdir HelloWorld
+
+
+
+
+
+
+
+ 3.
+
+
+
+Navigate into the new directory so that it is the terminal’s current location.
+
+
+cd HelloWorld
+
+
+
+
+
+
+
+ 4.
+
+
+
+Execute dotnet new console to generate the initial scaffolding (or project) for your program. While several files are generated, the two main files are Program.cs and the project file HelloWorld.csproj:
+
+
+dotnet new console
+
+
+
+
+
+
+
+ 5.
+
+
+
+Run the generated program. This compiles and runs the code created by the dotnet new console command. The content of Program.cs is similar to Listing1.1 but it outputs “Hello World!” instead.
+
+
+dotnet run
+
+
+
+
+
+
+
+ 6.
+
+
+
+Even though we don’t explicitly request the project to compile (or build)—via the dotnetbuild command, that step still occurs implicitly.
+
+
+
+
+
+
+
+ 7.
+
+
+
+Edit the Program.cs file and modify the code to match what is shown in Listing 1.1. If you use one of the editors mentioned to open and edit Program.cs, you will see the advantage of a C#-aware editor, as the code will be colorized to indicate the different types of constructs in your program. To open and edit using Visual Studio Code, use the following command or start Visual Studio Code and open the Program.cs file.
+
+
+code .
+
+
+
+
+
+
+
+ 8.
+
+
+
+(Alternatively, Output 1.1 shows an approach using only the command line that works for Bash and PowerShell.)
+
+
+
+
+
+
+
+ 9.
+
+
+
+ Rerun the program:
+
+
+dotnet run
+
+
+
+
+
+
+
+Output 1.1 shows the output following the preceding steps.5
+
+
+
+
+Output 1.1
+
+
+
+1>
+
+2> mkdir ./HelloWorld
+
+3> cd ./HelloWorld/
+
+4> dotnet new console
+
+The template "Console Application" was created successfully.
+
+
+
+Processing post-creation actions...
+
+Running 'dotnet restore' on C: \EssentialCSharp\HelloWorld\HelloWorld.csproj...
+
+ Restore completed in 100.38 ms for C:\EssentialCSharp\HelloWorld\HelloWorld.csproj.
+
+Restore succeeded.
+
+5> dotnet run
+
+Hello World!
+
+6> echo '
+
+Console.WriteLine("Hello. My name is Inigo Montoya.");
+
+' > Program.cs
+
+7> dotnet run
+
+Hello. My name is Inigo Montoya.
+
+
+
+
+
+
+
+
+With Visual Studio 2022 (Windows or Mac)
+
+
+
+
+
+With Visual Studio 2022, which runs only on Microsoft Windows or Mac, the procedure is similar, but instead of using the command line, you use an integrated development environment (IDE), which has menus you can choose from rather than executing everything from the command line:
+
+
+
+ 1.
+
+
+
+Launch Visual Studio 2022.
+
+
+
+
+
+
+
+ 2.
+
+
+
+Click the Create a new project button. (If the Start Window is not visible, you can open it from the File->Start Window menu or jump directly to create the project via the File->New Project (Ctrl+Shift+N) menu.)
+
+
+
+
+
+
+
+ 3.
+
+
+
+From the Search box (Alt+S), type Console App and select the Console App item (see Figure 1.2). (You can optionally select C# to reduce the options count if other languages are installed.)
+
+
+
+
+
+
+
+
+
+
+
+Figure1.2: The Create a new project dialog
+
+
+
+
+ 4.
+
+
+
+For the Project name text box, use HelloWorld, and for Location, select a working directory of your choosing (see Figure 1.3).
+
+
+
+
+
+
+
+
+
+
+
+Figure 1.3: The Configure your new project dialog
+
+
+
+
+ 5.
+
+
+
+At the Additional information dialog, choose .NET 7.0 in the Framework dropdown. (Leave the Do not use top-level statements checkbox unchecked.)
+
+
+
+
+
+
+
+ 6.
+
+
+
+Once the project is created, you should see a Program.cs file, as shown in Figure 1.4.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Figure 1.4: Dialog that shows the Program.cs file
+
+
+
+
+ 7.
+
+
+
+Run the generated program using the Debug->Start Without Debugging (Ctrl+F5) menu. This displays the terminal with the text shown in Output 1.2 except the first line displays “Hello World!” only.
+
+
+
+
+
+
+
+
+Output 1.2
+
+
+
+Hello. My name is Inigo Montoya.
+
+
+
+...\HelloWorld.exe (process 11856) exited with code 0.
+
+Press any key to close this window . . .
+
+
+
+
+
+
+
+ 8.
+
+
+
+Modify Program.cs to match Listing 1.1. Rerun the program to see the output shown in Output 1.2.
+
+
+
+
+
+
+
+
+
+
+Understanding a Project
+
+
+
+
+
+Whether using dotnet CLI or Visual Studio, there are several files created. The first file is a C# file with the name Program.cs by convention. The name Program is commonly used as the starting point for a console program, even though any name could be used. The .cs extension is the standard convention for all C# files and what the compiler expects to compile into the final program by default. To use the code shown in Listing 1.1, open the Program.cs file and replace its content with Listing 1.1. Before saving the updated file, observe that the only functional difference between Listing 1.1 and what was generated by default is the text between the double quotes.
+
+
+
+A configuration file called a project file is included as part of the generated source code of your C# project. The project file content varies from one application type and .NET framework to the next. However, at a minimum, it generally identifies what application type to build (console, web, library, etc.), which .NET framework(s) to support, compiler settings, and which potential settings are needed to launch the application, along with other dependencies the code may rely on (called libraries). For example, the simple .NET console application project file created in the previous section appears in Listing 1.2.
+
+
+
+
+Listing 1.2: Sample .NET Console Project File
+
+
+
+ 1.
+<Project Sdk="Microsoft.NET.Sdk">
+
+ 2.
+ <PropertyGroup>
+
+ 3.
+ <OutputType>Exe</OutputType>
+
+ 4.
+ <TargetFramework>net7.0</TargetFramework>
+
+ 5.
+ <ImplicitUsings>enable</ImplicitUsings>
+
+ 6.
+ <Nullable>enable</Nullable>
+
+ 7.
+ </PropertyGroup>
+
+ 8.
+</Project>
+
+
+
+
+
+
+In Listing 1.2, the application type is identified as a .NET 8.0 (net8.0) console application (Exe). The two other elements, Nullable (C# 8.0) and ImplicitUsings (C# 10.0) , will be discussed in “Declaring Types That Allow Null” in Chapter 3 and “Using Directives” in Chapter 5, respectively. All other settings (such as which C# files to compile) are identified by convention. For example, by default, all *.cs6 files in the same directory (or subdirectory) as the project file are included in the compile.
+
+
+
+
+
+
+Compilation and Execution
+
+
+
+
+
+When you execute dotnet run, it first implicitly runs dotnet build to compile the code. The compiled output created by the dotnet build command is an assembly called HelloWorld.dll.7 Assemblies contain a set of instructions specifying how a program will behave. The extension stands for dynamic link library (DLL), and with .NET, assemblies have a .dll extension even if they are console programs, as this one is. (On Windows, an .exe file is also created.) By default, the compiled output for a .NET application is placed into a subdirectory according to the TargetFramework identified in the project file, as shown in Listing 1.2 (./bin/Debug/net7.0/). The Debug directory is used because the default configuration is debug. This configuration causes the output to be optimized for debugging rather than for performance. The compiled output does not execute on its own. Rather, it needs the CLI to host the code. For .NET applications, this requires using the dotnet.exe (dotnet on Linux and Mac) process as a host process for the application. Hence why the program is executed with the dotnet run command. That said, there is a way to generate a stand-alone executable that includes the necessary runtime files so that installing the dotnet runtime is not required—see the “Advanced Topic: Publishing a Stand-Alone Executable” (On Windows, the .exe file can be used directly, if the dotnet runtime is installed, rather than using dotnetrun.)
+
+
+
+
+Essential C# Source Code
+
+
+
+
+
+Both the source code and the manuscript text are available at https://essentialcsharp.com. Alternatively, the source code for this book is available for download on GitHub directly at https://github.com/IntelliTect/EssentialCSharp. Instructions for compiling and running the code are available in the README.md file at the same location.
+
+
+
+An alternative approach is to paste the source code into the HelloWorld program created earlier in the chapter and then execute the source code.
+
+
+
+________________________________________
+
+
+ 1.
+ The first C# design meeting took place in 1998.
+
+
+ 2.
+ Refer to the movie The Princess Bride if you’re confused about the Inigo Montoya references.
+
+
+ 3.
+ This tool was released around the same time as C# 7.0, and it eclipsed compiling directly with the C# compiler, csc.exe.
+ 5.
+ The bold formatting in an Output indicates the user-entered content.
+
+
+ 6.
+ The “*” in *.cs is called a wildcard character, and matches any number of characters including none. In this instance, this identifies that any file ending in .cs will be included. If it was i*.cs it would include any files starting with an i and ending in .cs.
+
+
+ 7.
+ Note that if you use the Microsoft .NET Framework to create a console program, the compiled code is placed into a HelloWorld.exe file that you can execute directly assuming the Microsoft .NET Framework is installed on the computer.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/02.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/02.html
new file mode 100644
index 00000000..68fe1dd7
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/02.html
@@ -0,0 +1,3142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+C# Syntax Fundamentals
+
+
+
+
+
+Once you successfully compile and run the HelloWorld program, you are ready to start dissecting the code to learn its individual parts. Of course, Listing 1.1 is the simplest of C# programs with only a single statement.
+
+
+
+Statements and Statement Delimiters
+
+
+
+
+
+The single statement is Console.WriteLine(), which is used to write a line of text to the console. C# generally uses a semicolon to indicate the end of a statement, where a statement comprises one or more actions that the code will perform. Declaring a variable, controlling the program flow, and calling a method are typical uses of statements.
+
+
+
+
+
AdVanced Topic
+
Statements without Semicolons
+
+
+
+
+
+Many programming elements in C# end with a semicolon. One example that does not include the semicolon is a switch statement. Because curly braces are always included in a switch statement, C# does not require a semicolon following the statement. In fact, code blocks themselves are considered statements (they are also composed of statements), and they don’t require ending with a semicolon. Similarly, there are cases, such as the using declaration, in which a semicolon appears as a postfix, but it is not a statement.
+
+
+
+Since creation of a newline does not separate statements, you can place multiple statements on the same line, and the C# compiler will interpret the line as having multiple instructions. For example, Listing 1.3 contains two statements on a single line that, in combination, display Up and Down on two separate lines.
+Similarly, each statement can be placed on its own line, as shown in Listing 1.4.
+
+
+
+
+Listing 1.4: Multiple Statements Each on Separate Lines
+
+
+
+ 1.
+Console.WriteLine("Down");
+
+ 2.
+Console.WriteLine("Side");
+
+ 3.
+Console.WriteLine("Up");
+
+
+
+
+
+
+C# also allows the splitting of a statement across multiple lines. Again, the C# compiler looks for a semicolon to indicate the end of a statement. In Listing 1.5, for example, the original WriteLine() statement from the HelloWorld program is split across multiple lines.
+
+
+
+
+Listing 1.5: Splitting a Single Statement across Multiple Lines
+
+
+
+ 1.
+Console.WriteLine(
+
+ 2.
+ "Hello. My name is Inigo Montoya.");
+
+
+
+
+
+
+Introducing a Class and a Method
+
+
+
+
+
+In the listings shown so far, the statements are independent of any other C# constructs and appear this way in only a single file. The previous listings are the simplest of C# programs, a HelloWorld program, after all. Programs can, however, get vastly more complicated, and structure can be added to organize the code. The simplest structure is to add methods and to place those methods within classes. Listing 1.6 provides an example.
+
+
+
+
+Listing 1.6: HelloWorld with Class and Method
+
+
+
+ 1.
+publicclass Program
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ System.Console.WriteLine("Hello. My name is Inigo Montoya.");
+
+ 6.
+ }
+
+ 7.
+}
+
+
+
+
+
+
+In this listing, the HelloWorld statement is placed into a method called Main, which is placed into a class called Program.
+
+
+
+Those experienced in programming with Java, C, or C++ will immediately see similarities. Like Java, C# inherits its basic syntax from C and C++.8 Syntactic punctuation (such as semicolons and curly braces), features (such as case sensitivity), and keywords (such as class, public, and void) are familiar to programmers experienced in these languages.
+
+
+
+
+
+
+
+
+
+
+ note
+
+
+
+
+C# is a case-sensitive language: Incorrect case prevents the code from compiling successfully.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Language Contrast: Java—Filename Must Match Class Name
+
+
+
+
+
+
+
+In Java, the filename must follow the name of the class. In C#, this convention is frequently followed but is not required. In C#, it is possible to have two classes in one file, and even to have a single class span multiple files, with a feature called a partial class.
+
+
+
+
+
+
+
+
+
+
+
+
+
Beginner Topic
+
Keywords
+
+
+
+
+
+To enable the compiler to interpret the code, certain words within C# have special status and meaning. Known as keywords, they provide the concrete syntax that the compiler uses to interpret the expressions the programmer writes. In the HelloWorld program, class, static, and void are examples of keywords.
+
+
+
+The compiler uses the keywords to identify the structure and organization of the code. Because the compiler interprets these words with elevated significance, C# requires that developers place keywords only in certain locations. When programmers violate these rules, the compiler issues errors.
+
+
+
+
+
+
+
+
+
+
+
+
+
+C# Keywords
+
+
+
+
+
+Keywords are another construct common to other programming languages. Table 1.1 shows the C# keywords.
+
+
+
+
Table 1.1:C# Keywords
+
+
+
+
+
+
+
+
+
+
+
+abstract
+
+
+
+
+
+
+add*(1)
+
+
+
+
+
+
+alias*(2)
+
+
+
+
+
+
+and*
+
+
+
+
+
+
+
+
+
+
+args*
+
+
+
+
+
+
+as
+
+
+
+
+
+
+ascending*(3)
+
+
+
+
+
+
+async*(5)
+
+
+
+
+
+
+
+
+
+
+await*(5)
+
+
+
+
+
+
+base
+
+
+
+
+
+
+bool
+
+
+
+
+
+
+break
+
+
+
+
+
+
+
+
+
+
+by*(3)
+
+
+
+
+
+
+byte
+
+
+
+
+
+
+case
+
+
+
+
+
+
+catch
+
+
+
+
+
+
+
+
+
+
+char
+
+
+
+
+
+
+checked
+
+
+
+
+
+
+class
+
+
+
+
+
+
+const
+
+
+
+
+
+
+
+
+
+
+continue
+
+
+
+
+
+
+decimal
+
+
+
+
+
+
+default
+
+
+
+
+
+
+delegate
+
+
+
+
+
+
+
+
+
+
+descending*(3)
+
+
+
+
+
+
+do
+
+
+
+
+
+
+double
+
+
+
+
+
+
+dynamic*(4)
+
+
+
+
+
+
+
+
+
+
+else
+
+
+
+
+
+
+enum
+
+
+
+
+
+
+equals*(3)
+
+
+
+
+
+
+event
+
+
+
+
+
+
+
+
+
+
+explicit
+
+
+
+
+
+
+extern
+
+
+
+
+
+
+false
+
+
+
+
+
+
+file*
+
+
+
+
+
+
+
+
+
+
+finally
+
+
+
+
+
+
+fixed
+
+
+
+
+
+
+float
+
+
+
+
+
+
+for
+
+
+
+
+
+
+
+
+
+
+foreach
+
+
+
+
+
+
+from*(3)
+
+
+
+
+
+
+get*(1)
+
+
+
+
+
+
+global*(2)
+
+
+
+
+
+
+
+
+
+
+goto
+
+
+
+
+
+
+group*(3)
+
+
+
+
+
+
+if
+
+
+
+
+
+
+implicit
+
+
+
+
+
+
+
+
+
+
+in
+
+
+
+
+
+
+init*(9)
+
+
+
+
+
+
+int
+
+
+
+
+
+
+interface
+
+
+
+
+
+
+
+
+
+
+internal
+
+
+
+
+
+
+into*(3)
+
+
+
+
+
+
+is
+
+
+
+
+
+
+join*(3)
+
+
+
+
+
+
+
+
+
+
+let*(3)
+
+
+
+
+
+
+lock
+
+
+
+
+
+
+long
+
+
+
+
+
+
+nameof*(6)
+
+
+
+
+
+
+
+
+
+
+namespace
+
+
+
+
+
+
+new
+
+
+
+
+
+
+nint*(9)
+
+
+
+
+
+
+not*
+
+
+
+
+
+
+
+
+
+
+notnull*(8)
+
+
+
+
+
+
+null
+
+
+
+
+
+
+nunit*(9)
+
+
+
+
+
+
+object
+
+
+
+
+
+
+
+
+
+
+on*(3)
+
+
+
+
+
+
+operator
+
+
+
+
+
+
+or*
+
+
+
+
+
+
+orderby*(3)
+
+
+
+
+
+
+
+
+
+
+out
+
+
+
+
+
+
+override
+
+
+
+
+
+
+params
+
+
+
+
+
+
+partial*(2)
+
+
+
+
+
+
+
+
+
+
+private
+
+
+
+
+
+
+protected
+
+
+
+
+
+
+public
+
+
+
+
+
+
+readonly
+
+
+
+
+
+
+
+
+
+
+record*
+
+
+
+
+
+
+ref
+
+
+
+
+
+
+remove*(1)
+
+
+
+
+
+
+required*(11)
+
+
+
+
+
+
+
+
+
+
+return
+
+
+
+
+
+
+sbyte
+
+
+
+
+
+
+scoped*
+
+
+
+
+
+
+sealed
+
+
+
+
+
+
+
+
+
+
+select*(3)
+
+
+
+
+
+
+set*(1)
+
+
+
+
+
+
+short
+
+
+
+
+
+
+sizeof
+
+
+
+
+
+
+
+
+
+
+stackalloc
+
+
+
+
+
+
+static
+
+
+
+
+
+
+string
+
+
+
+
+
+
+struct
+
+
+
+
+
+
+
+
+
+
+switch
+
+
+
+
+
+
+this
+
+
+
+
+
+
+throw
+
+
+
+
+
+
+TRUE
+
+
+
+
+
+
+
+
+
+
+try
+
+
+
+
+
+
+typeof
+
+
+
+
+
+
+uint
+
+
+
+
+
+
+ulong
+
+
+
+
+
+
+
+
+
+
+unchecked
+
+
+
+
+
+
+unmanaged*(7.3)
+
+
+
+
+
+
+unsafe
+
+
+
+
+
+
+ushort
+
+
+
+
+
+
+* Contextual keyword. Numbers in parentheses (n) identify in which version the contextual keyword was added.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+After C# 1.0, no new reserved keywords were introduced to C#. However, some constructs in later versions use contextual keywords, which are significant only in specific locations. Outside these designated locations, contextual keywords have no special significance.9 By this method, even C# 1.0 code is compatible with the later standards.10
+
+
+
+
+Identifiers
+
+
+
+
+
+Like other languages, C# includes identifiers to identify constructs that the programmer codes. In Listing 1.6, HelloWorld and Main are examples of identifiers. The identifiers assigned to a construct are used to refer to the construct later, so it is important that the names the developer assigns are meaningful rather than arbitrary.
+
+
+
+
+
+
+
+
+
+
+ note
+
+
+
+
+A keen ability to select succinct and indicative names is an important characteristic of a strong programmer because it means the resultant code will be easier to understand and reuse.
+
+
+
+
+
+
+
+
+
+
+
+Clarity coupled with consistency is important enough that the Framework Design Guidelines (http://bit.ly/dotnetguidelines) advise against the use of abbreviations or contractions in identifier names and even recommend avoiding acronyms that are not widely accepted. If an acronym is sufficiently well established (e.g., HTML), you should use it consistently. Avoid spelling out the accepted acronym in some cases but not in others. Generally, adding the constraint that all acronyms be included in a glossary of terms places enough overhead on the use of acronyms that they are not used flippantly. Ultimately, select clear, possibly even verbose names—especially when working on a team or when developing a library that other developers will use.
+
+
+
+There are two basic casing formats for an identifier. Pascal case (henceforth PascalCase), as the .NET framework creators refer to it because of its popularity in the Pascal programming language, capitalizes the first letter of each word in an identifier name; examples include ComponentModel, Configuration, and HttpFileCollection. As HttpFileCollection demonstrates with HTTP, when using acronyms that are more than two letters long, only the first letter is capitalized. The second format, camel case (henceforth camelCase), follows the same convention except that the first letter is lowercase; examples include quotient, firstName, httpFileCollection, ioStream, and theDreadPirateRoberts.
+
+
+
+
+
+
+
+
+
+
+
+Guidelines
+
+
+DO favor clarity over brevity when naming identifiers.
+
+DO NOT use abbreviations or contractions within identifier names.
+
+DO NOT use any acronyms unless they are widely accepted, in which case use them consistently.
+
+
+
+
+
+
+
+
+
+
+Notice that although underscores are legal, generally there are no underscores, hyphens, or other nonalphanumeric characters in identifier names. Furthermore, C# doesn’t follow its predecessors in that Hungarian notation (prefixing a name with a data type abbreviation) is not used. This convention avoids the variable rename that is necessary when data types change, or the inconsistency introduced due to failure to adjust the data type prefix when using Hungarian notation.
+
+
+
+In rare cases, some identifiers, such as Main, can have a special meaning in the C# language.
+
+
+
+While naming guidelines may seem relatively trivial, especially when coming from other languages where such guidelines are ambiguous or missing entirely, violations of these guidelines will be glaring to an experienced C#/.NET programmer and indicate poor quality or inexperience. To avoid this, learn the guidelines, and follow them religiously.
+
+
+
+
+
+
+
+
+
+
+
+Guidelines
+
+
+DO capitalize both characters in two-character acronyms, except for the first word of a camelCased identifier.
+
+DO capitalize only the first character in acronyms with three or more characters, except for the first word of a camelCased identifier.
+
+DO NOT capitalize any of the characters in acronyms at the beginning of a camelCased identifier.
+
+DO NOT use Hungarian notation (that is, do not encode the type of a variable in its name).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
AdVanced Topic
+
Keywords
+
+
+
+
+
+Although it is rare, keywords may be used as identifiers if they include @ as a prefix. For example, you could name a local variable @return. Similarly (although it doesn’t conform to the casing standards of C# coding standards), it is possible to name a method @throw, with parentheses following: @throw().
+
+
+
+There are also four undocumented reserved keywords in the Microsoft implementation: __arglist, __makeref, __reftype, and __refvalue. These are required only in rare interop scenarios, and you can ignore them for all practical purposes. Note that these four special keywords begin with two underscores. The designers of C# reserve the right to make any identifier that begins with two underscores into a keyword in a future version; for safety, avoid ever creating such an identifier yourself.
+
+
+
+Type Definition
+
+
+
+
+
+A class definition is the section of code that generally begins with class <identifier> { ... }, as shown in Listing 1.7, where HelloWorld is the identifier.
+
+
+
+
+Listing 1.7: Basic Class Declaration
+
+
+
+ 1.
+publicclass HelloWorld
+
+ 2.
+{
+
+ 3.
+ // ...
+
+ 4.
+}
+
+
+
+
+
+
+The name used for the type (in this case, HelloWorld) can vary, but by convention, it must be PascalCased. For this example, therefore, other possible names are Greetings, HelloInigoMontoya, Hello, or simply Program. (Program is a good convention to follow when the class contains the Main() method, described next.)
+
+
+
+
+
+
+
+
+
+
+
+Guidelines
+
+
+DO name classes with nouns or noun phrases.
+
+DO use PascalCasing for all class names.
+
+
+
+
+
+
+
+
+
+
+Generally, programs contain multiple types, each containing multiple methods.
+
+
+
+
+
+
+
+
+
Beginner Topic
+
What Is a Method?
+
+
+
+
+
+Syntactically, a method in C# is a named block of code introduced by a method declaration (e.g., static void Main()) and (usually) followed by zero or more statements within curly braces. Methods perform computations and/or actions. Like paragraphs in written languages, methods provide a means of structuring and organizing code so that it is more readable. More important, methods can be reused and called from multiple places and so avoid the need to duplicate code. The method declaration introduces the method and defines the method name along with the data passed to and from the method. In Listing 1.8, Main() followed by { ... } is an example of a C# method.
+
+
+
+Main Method
+
+
+
+
+
+The location where C# programs begin execution is the Main method, which begins with static void Main(). When you execute the program by typing dotnet run on the terminal, the program starts with the Main method and begins executing the first statement, as identified in Listing 1.8.
+
+
+
+
+
+
+Listing 1.8: Breaking Apart HelloWorld
+
+
+
+ 1.
+publicclass Program // BEGIN Class definition
+ 5.
+ Console.WriteLine( // This statement spans 2 lines
+
+ 6.
+ "Hello, My name is Inigo Montoya");
+
+ 7.
+ } // END method implementation
+
+ 8.
+} // END class definition
+
+
+
+
+
+
+Although the Main method declaration can vary to some degree, static and the method name, Main, are always required for a program (see “Advanced Topic: Declaration of the Main Method”).
+
+
+
+The comments, text that begins with // in Listing 1.8, are explained later in the chapter. They are included to identify the various constructs in the listing.
+
+
+
+
+
AdVanced Topic
+
Declaration of the Main Method
+
+
+
+
+
+C# requires that the Main method return either void or int and that it take either no parameters or a single array of strings. Listing 1.9 shows the full declaration of the Main method. The args parameter is an array of strings corresponding to the command-line arguments. The executable name is not included in the args array (unlike in C and C++). To retrieve the full command used to execute the program, including the program name, use Environment.CommandLine.
+
+
+
+
+Listing 1.9:The Main Method with Parameters and a Return
+
+
+
+ 1.
+publicstaticint Main(string[] args)
+
+ 2.
+{
+
+ 3.
+ // ...
+
+ 4.
+}
+
+
+
+
+
+
+The int returned from Main() is the status code, and it indicates the success of the program’s execution. A return of a nonzero value generally indicates an error.
+
+
+
+C# 7.1 also added support for async/await on the Main method, in which case you would use Task-based types in the return.
+
+
+
+
+
+
+
+
+
+
+ note
+
+
+
+
+All Lowercase
+
+Unlike its C-style predecessors, C# uses an uppercase M for the Main method to be consistent with the PascalCased naming conventions of C#.
+
+
+
+
+
+
+
+
+
+
+
+The designation of the Main method as static indicates that other methods may call it directly off the class definition. Without the static designation, the terminal that started the program would need to perform additional work (known as instantiation) before calling the method. (Chapter 6 contains an entire section devoted to the topic of static members.)
+
+
+
+Placing void prior to Main() indicates that this method does not return any data. (This is explained further in Chapter 2.)
+
+
+
+One distinctive C/C++-style characteristic followed by C# is the use of curly braces for the body of a construct, such as the class or the method. For example, the Main method contains curly braces that surround its implementation; in this case, only one statement appears in the method.
+
+
+
+
+
Beginner Topic
+
What Is Whitespace?
+
+
+
+
+
+Whitespace is the combination of one or more consecutive formatting characters such as tab, space, and newline characters. Eliminating all whitespace between words is obviously significant, as is including whitespace within a quoted string.
+
+
+
+Whitespace
+
+
+
+
+
+The semicolon makes it possible for the C# compiler to ignore whitespace in code. Apart from a few exceptions, C# allows developers to insert whitespace throughout the code without altering its semantic meaning. In Listing 1.8 and Listing 1.9, it didn’t matter whether a newline was inserted within a statement, between statements, or eliminated entirely, and doing so had no effect on the resultant executable created by the compiler.
+
+
+
+Frequently, programmers use whitespace to indent code for greater readability. Consider the two variations on HelloWorld shown in Listing 1.10 and Listing 1.11. Although these two examples look significantly different from the original program, the C# compiler sees them as semantically equivalent.
+Indenting the code using whitespace is important for greater readability. As you begin writing code, you need to follow established coding standards and conventions to enhance code readability.
+
+
+
+The convention used in this book is to place curly braces on their own line and to indent the code contained between the curly brace pair. If another curly brace pair appears within the first pair, all the code within the second set of braces is also indented.
+
+
+
+This is not a uniform C# standard but a stylistic preference.
+
+
+
+________________________________________
+
+
+ 8.
+ When creating C#, the language creators reviewed the specifications for C/C++, literally crossing out the features they didn’t like and creating a list of the ones they did like. The group also included designers with strong backgrounds in other languages.
+
+
+ 9.
+ For example, early in the design of C# 2.0, the language designers designated yield as a keyword, and Microsoft released alpha versions of the C# 2.0 compiler, with yield as a designated keyword, to thousands of developers. However, the language designers eventually determined that by using yield return rather than yield, they could ultimately avoid adding yield as a keyword because it would have no special significance outside its proximity to return.
+
+
+ 10.
+ There are some rare and unfortunate incompatibilities, such as the following: C# 2.0 requires implementation of IDisposable with the using statement rather than simply using a Dispose() method. Some rare generic expressions are different between versions. For example, F(G<A,B>(7)) means F((G<A), (B>7)) in C# 1.0, but in C# 2.0, it means to call generic method G<A,B> with argument 7 and pass the result to F.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/03.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/03.html
new file mode 100644
index 00000000..bec185ee
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/03.html
@@ -0,0 +1,1593 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Working with Variables
+
+
+
+
+
+Now that you’ve been introduced to the most basic C# program, it’s time to declare a local variable. Once a variable is declared, you can assign it a value, replace that value with a new value, and use it in calculations, output, and so on. However, you cannot change the data type of the variable. In Listing 1.12, string max is a variable declaration.
+
+
+
+
+
+
+Listing 1.12: Declaring and Assigning a Variable
+
+
+
+ 1.
+publicclass MiracleMax
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ string max; // "string" identifies the data type
+
+ 6.
+ // "max" is the variable
+
+ 7.
+ max = "Have fun storming the castle!";
+
+ 8.
+ Console.WriteLine(max);
+
+ 9.
+ }
+
+ 10.
+}
+
+
+
+
+
+
+
+
Beginner Topic
+
Local Variables
+
+
+
+
+
+A variable is a name that refers to a value that can change over time. Local indicates that the programmer declared the variable within a method.
+
+
+
+To declare a variable is to define it, which you do by
+
+
+
+
+
+ •
+
+
+
+Specifying the type of data which the variable will contain
+
+
+
+
+
+ •
+
+
+
+Assigning it an identifier (name)
+
+
+
+
+
+
+Introducing Data Types
+
+
+
+
+
+Listing 1.12 declares a variable with the data type string. Other common data types used in this chapter are int and char.
+
+
+
+
+
+ •
+
+
+
+int is the C# designation of an integer type that is 32 bits in size.
+
+
+
+
+
+ •
+
+
+
+char is used for a character type. It is 16 bits, large enough for (nonsurrogate) Unicode characters.
+
+
+
+
+
+
+The next chapter looks at these and other common data types in more detail.
+
+
+
+
+
Beginner Topic
+
What Is a Data Type?
+
+
+
+
+
+The type of data that a variable declaration specifies is called a data type (or object type). A data type, or simply type, is a classification of things that share similar characteristics and behavior. For example, animal is a type. It classifies all things (monkeys, warthogs, and platypuses) that have animal characteristics (multicellular, capacity for locomotion, and so on). Similarly, in programming languages, a type is a definition for several items endowed with similar qualities.
+
+
+
+Declaring a Variable
+
+
+
+
+
+In Listing 1.12, string max is a variable declaration of a string type whose name is max. It is possible to declare multiple variables within the same statement by specifying the data type once and separating each identifier with a comma. Listing 1.13 demonstrates such a declaration.
+
+
+
+
+Listing 1.13: Declaring Two Variables within One Statement
+
+
+
+ 1.
+string message1, message2;
+
+
+
+
+
+
+Because a multivariable declaration statement allows developers to provide the data type only once within a declaration, all variables will be of the same type.
+
+
+
+In C#, the name of the variable may begin with any letter or an underscore (_), followed by any number of letters, numbers, and/or underscores. By convention, however, local variable names are camelCased (the first letter in each word is capitalized, except for the first word) and do not include underscores.
+
+
+
+
+
+
+
+
+
+
+
+Guidelines
+
+
+DO use camelCasing for local variable names.
+
+
+
+
+
+
+Assigning a Variable
+
+
+
+
+
+After declaring a local variable, you must assign it a value before reading from it. One way to do this is to use the =operator, also known as the simple assignment operator. Operators are symbols used to identify the function the code is to perform. Listing 1.14 demonstrates how to use the assignment operator to designate the string values to which the variables miracleMax and valerie will point.
+
+
+
+
+Listing 1.14: Changing the Value of a Variable
+
+
+
+ 1.
+publicclass StormingTheCastle
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ string valerie;
+
+ 6.
+ string miracleMax = "Have fun storming the castle!";
+
+ 7.
+
+
+ 8.
+ valerie = "Think it will work?";
+
+ 9.
+
+
+ 10.
+ Console.WriteLine(miracleMax);
+
+ 11.
+ Console.WriteLine(valerie);
+
+ 12.
+
+
+ 13.
+ miracleMax = "It would take a miracle.";
+
+ 14.
+ Console.WriteLine(miracleMax);
+
+ 15.
+ }
+
+ 16.
+}
+
+
+
+
+
+
+From this listing, observe that it is possible to assign a variable as part of the variable declaration (as it was for miracleMax) or afterward in a separate statement (as with the variable valerie). The value assigned must always be on the right side of the declaration.
+
+
+
+Running the compiled program produces the code shown in Output 1.3.
+
+
+
+
+Output 1.3
+
+
+
+>dotnet run
+
+Have fun storming the castle!
+
+Think it will work?
+
+It would take a miracle.
+
+
+
+
+
+
+
+
+
+
+
+In this example, we show the command dotnetrun explicitly. In future output listings, we will omit this line unless there is something special about the command used to execute the program.
+
+
+
+C# requires that local variables be (as determined by the compiler) “definitely assigned” before they are read. Additionally, an assignment results in a value. Therefore, C# allows two assignments within the same statement, as demonstrated in Listing 1.15.
+
+
+
+
+Listing 1.15: Assignment Returning a Value That Can Be Assigned Again
+
+
+
+ 1.
+publicclass StormingTheCastle
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ // ...
+
+ 6.
+ string requirements, miracleMax;
+
+ 7.
+ requirements = miracleMax = "It would take a miracle.";
+
+ 8.
+ // ...
+
+ 9.
+ }
+
+ 10.
+}
+
+
+
+
+
+
+Using a Variable
+
+
+
+
+
+The result of the assignment, of course, is that you can then refer to the value using the variable identifier. Therefore, when you use the variable miracleMax within the Console.WriteLine(miracleMax) statement, the program displays “Have fun storming the castle!”—the value of miracleMax—on the console. Changing the value of miracleMax and executing the same Console.WriteLine(miracleMax) statement displays the new miracleMax value, “It would take a miracle.”
+
+
+
+
+
AdVanced Topic
+
Strings Are Immutable
+
+
+
+
+
+All values of type string, whether string literals or otherwise, are immutable (or unmodifiable). For example, it is not possible to change the string Come As You Are. to Come As You Age. A change such as this requires that you reassign the variable instead of modifying the data to which the variable originally referred.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/04.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/04.html
new file mode 100644
index 00000000..da32abda
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/04.html
@@ -0,0 +1,2182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Console Input and Output
+
+
+
+
+
+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.
+
+
+
+Getting Input from the Console
+
+
+
+
+
+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.
+
+
+
+
+Listing 1.16: Using Console.ReadLine()
+
+
+
+ 1.
+publicclass HeyYou
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ string firstName;
+
+ 6.
+ string lastName;
+
+ 7.
+
+
+ 8.
+ Console.WriteLine("Hey you!");
+
+ 9.
+
+
+ 10.
+ Console.Write("Enter your first name: ");
+
+ 11.
+ firstName = Console.ReadLine();
+
+ 12.
+
+
+ 13.
+ Console.Write("Enter your last name: ");
+
+ 14.
+ lastName = Console.ReadLine();
+
+ 15.
+ }
+
+ 16.
+}
+
+
+
+
+
+
+
+Output 1.4
+
+
+
+Hey you!
+
+Enter your first name: Inigo
+
+Enter your last name: Montoya
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
+
AdVanceD Topic
+
System.Console.Read()
+
+
+
+
+
+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.
+
+
+
+
+Listing 1.17: Using System.Console.Read()
+
+
+
+ 1.
+int readValue;
+
+ 2.
+char character;
+
+ 3.
+readValue = Console.Read();
+
+ 4.
+character = (char) readValue;
+
+ 5.
+Console.Write(character);
+
+
+
+
+
+
+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.
+
+
+
+
+Writing Output to the Console
+
+
+
+
+
+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.
+
+
+
+
+Listing 1.18: Formatting Using String Interpolation
+
+
+
+ 1.
+publicclass HeyYou
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ string firstName;
+
+ 6.
+ string lastName;
+
+ 7.
+
+
+ 8.
+ Console.WriteLine("Hey you!");
+
+ 9.
+
+
+ 10.
+ Console.Write("Enter your first name: ");
+
+ 11.
+ firstName = Console.ReadLine();
+
+ 12.
+
+
+ 13.
+ Console.Write("Enter your last name: ");
+
+ 14.
+ lastName = Console.ReadLine();
+
+ 15.
+
+
+ 16.
+ Console.WriteLine(
+
+ 17.
+ $"Your full name is { firstName }{ lastName }.");
+
+ 18.
+ }
+
+ 19.
+}
+
+
+
+
+
+
+
+Output 1.5
+
+
+
+Hey you!
+
+Enter your first name: Inigo
+
+Enter your last name: Montoya
+
+
+
+Your full name is Inigo Montoya.
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
+Listing 1.19: Formatting Using Console.WriteLine()’s Composite Formatting
+
+
+
+ 1.
+publicclass HeyYou
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ string firstName;
+
+ 6.
+ string lastName;
+
+ 7.
+
+
+ 8.
+ Console.WriteLine("Hey you!");
+
+ 9.
+
+
+ 10.
+ Console.Write("Enter your first name: ");
+
+ 11.
+ firstName = Console.ReadLine();
+
+ 12.
+
+
+ 13.
+ Console.Write("Enter your last name: ");
+
+ 14.
+ lastName = Console.ReadLine();
+
+ 15.
+
+
+ 16.
+ Console.WriteLine(
+
+ 17.
+ "Your full name is {0} {1}.", firstName, lastName);
+
+ 18.
+ }
+
+ 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).
+
+
+
+
+Listing 1.20: Swapping the Indexed Placeholders and Corresponding Variables
+
+
+
+ 1.
+Console.WriteLine("Your full name is {1}, {0}.", firstName, lastName);
+
+
+
+
+
+
+
+Output 1.6
+
+
+
+Hey you!
+
+Enter your first name: Inigo
+
+Enter your last name: Montoya
+
+
+
+Your full name is Montoya, Inigo
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
+
+
+
+
+
+
+ note
+
+
+
+
+Since string interpolation is almost always easier to understand than the alternative composite string approach, throughout the remainder of the book we use string interpolation by default.
+
+
+
+
+
+
+
+Comments
+
+
+
+
+
+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.
+
+
+
+
+
+Listing 1.21: Commenting Your Code
+
+
+
+ 1.
+publicclass CommentSamples
+
+ 2.
+{
+
+ 3.
+ publicstaticvoid Main()
+
+ 4.
+ {
+
+ 5.
+ string firstName; // Variable for storing the first name
+
+ 6.
+ string lastName; // Variable for storing the last name
+
+ 7.
+
+
+ 8.
+ Console.WriteLine("Hey you!");
+
+ 9.
+
+
+ 10.
+ Console.Write /* No new line */ ("Enter your first name: ");
+
+ 11.
+ firstName = Console.ReadLine();
+
+ 12.
+
+
+ 13.
+ Console.Write /* No new line */ ("Enter your last name: ");
+
+ 14.
+ lastName = Console.ReadLine();
+
+ 15.
+
+
+ 16.
+ /* Display a greeting to the console
+
+ 17.
+ using composite formatting. */
+
+ 18.
+
+
+ 19.
+ Console.WriteLine("Your full name is {1}, {0}.",
+
+ 20.
+ firstName, lastName);
+
+ 21.
+ // This is the end
+
+ 22.
+ // of the program listing
+
+ 23.
+ }
+
+ 24.
+}
+
+
+
+
+
+
+
+Output 1.7
+
+
+
+Hey you!
+
+Enter your first name: Inigo
+
+Enter your last name: Montoya
+
+
+
+Your full name is Inigo Montoya.
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
Table 1.2: C# Comment Types
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
+
+
+
+
+
+
+
+Guidelines
+
+
+DO NOT use comments unless they describe something that is not obvious to someone other than the developer who wrote the code.
+
+DO favor writing clearer code over entering comments to clarify a complicated algorithm.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Beginner Topic
+
Extensible Markup Language
+
+
+
+
+
+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.
+
+
+
+Debugging
+
+
+
+
+
+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:
+
+
+
+ 1.
+
+
+
+With the latest version of Program.cs open (Listing 1.9), put your cursor on the last Console.WriteLine line and click the Debug->Toggle Breakpoint (F9) menu item to activate a breakpoint on that line.
+
+
+
+
+
+
+
+ 2.
+
+
+
+In Visual Studio, click the Debug->Start Debugging (F5) menu to relaunch the application but this time with debugging activated.
+
+
+
+
+
+
+
+ 3.
+
+
+
+Visual Studio Code is similar except the menu is Run->Start Debugging (F5). Visual Studio Code also displays a notification to create the build and debug assets, the launch.json and tasks.json files, if you haven’t created them already. Because of the Console.ReadLine statement, you will also need to change the console line in the launch.json file to use “integratedTerminal” rather than “internalConsole.” Now, when debugging, be sure to switch to the TERMINAL output window to respond to your program’s prompts.
+
+
+
+
+
+
+
+ 4.
+
+
+
+Once debugging starts, execution will stop on the line where you set the breakpoint. You can then hover your cursor over a variable (e.g., firstName) to see its value.
+
+
+
+
+
+
+
+ 5.
+
+
+
+In Visual Studio, you can even move the execution of the program from the current line to another line within the method by dragging the yellow arrow in the left margin of the file window.
+
+
+
+
+
+
+
+ 6.
+
+
+
+To continue the program execution, use the Continue button for either IDE (or the Debug->Continue (F5) menu in Visual Studio or Run->Continue (F5) in Visual Studio Code).
+
+
+
+
+
+
+
+For more information about debugging, see the links corresponding to each version:
+ 13.
+ XML delimited comments were explicitly added only in C# 2.0, but the syntax is compatible with C# 1.0.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/05.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/05.html
new file mode 100644
index 00000000..155b772e
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/05.html
@@ -0,0 +1,1663 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Managed Execution and the Common Language Infrastructure
+
+
+
+
+
+The processor cannot directly interpret an assembly. .NET assemblies consist mainly of a second language known as Common Intermediate Language(CIL), or IL for short.14 The C# compiler transforms the C# source file into this intermediate language. An additional step, usually performed at execution time, is required to change the CIL code into machine code that the processor can understand. This involves an important element in the execution of a C# program: the Virtual Execution System (VES). The VES, also casually referred to as the runtime, compiles CIL code as needed (a process known as just-in-time compilation or jitting). The code that executes under the context of an agent such as the runtime is termed managed code, and the process of executing under control of the runtime is called managed execution. The code is “managed” because the runtime controls significant portions of the program’s behavior by managing aspects such as memory allocation, security, and just-in-time compilation. Code that does not require the runtime to execute is called native code (or unmanaged code).
+
+
+
+The specification for a runtime is included in a broader specification known as the Common Language Infrastructure (CLI) specification.15 An international standard, the CLI includes specifications for the following:
+
+
+
+
+
+
+ note
+
+
+
+
+The term runtime can refer to either execution time or the VES. To help clarify the intended meaning, this book uses the term execution time to indicate when the program is executing, and it uses the term runtime when discussing the agent responsible for managing the execution of a C# program while it executes.
+
+
+
+
+
+
+
+
+
+ •
+
+
+
+The VES or runtime
+
+
+
+
+
+ •
+
+
+
+The CIL
+
+
+
+
+
+ •
+
+
+
+A type system that supports language interoperability, known as the Common Type System (CTS)
+
+
+
+
+
+ •
+
+
+
+Guidance on how to write libraries that are accessible from CLI-compatible languages (available in the Common Language Specification [CLS])
+
+
+
+
+
+ •
+
+
+
+Metadata that enables many of the services identified by the CLI (including specifications for the layout or file format of assemblies)
+
+
+
+
+
+
+
+
+
+
+Running within the context of a runtime execution engine enables support for several services and features that programmers do not need to code for directly, including the following:
+
+
+
+
+
+
+ note
+
+
+
+
+This section provides a brief synopsis of the CLI to familiarize you with the context in which a C# program executes. It also provides a summary of some of the terms that appear throughout this book. Chapter 24 is devoted to the topic of the CLI and its relevance to C# developers. Although the chapter appears last in the book, it does not depend on any earlier chapters, so if you are eager to become more familiar with the CLI, you can jump to it at any time.
+
+
+
+
+
+
+
+
+
+ •
+
+
+
+Language interoperability: Interoperability between different source languages. This is possible because the language compilers translate each source language to the same intermediate language (CIL).
+
+
+
+
+
+ •
+
+
+
+Type safety: Checks for conversion between types, ensuring that only conversions between compatible types occurs. This helps prevent the occurrence of buffer overruns, a leading cause of security vulnerabilities.
+
+
+
+
+
+ •
+
+
+
+Code access security: Certification that the assembly developer’s code has permission to execute on the computer.
+
+
+
+
+
+ •
+
+
+
+Garbage collection: Memory management that automatically de-allocates memory previously allocated by the runtime.
+
+
+
+
+
+ •
+
+
+
+Platform portability: Support for running the same assembly on a variety of operating systems.
+
+
+
+
+
+ •
+
+
+
+Base Class Library (BCL): Provides a foundation of code that developers can depend on so that they do not have to develop the code themselves.
+
+
+
+
+
+
+Common Intermediate Language and Ildasm
+
+
+
+
+
+As mentioned in the introduction of this section, the C# compiler converts C# code to CIL code and not to machine code. The processor can directly understand machine code; therefore, CIL code needs to be converted before the processor can execute it. Given an assembly, it is possible to view the CIL code using a CIL disassembler utility to deconstruct the assembly into its CIL representation. (The CIL disassembler is affectionately referred to by its Microsoft .NET Framework–specific filename, Ildasm, which stands for IL Disassembler.) Ildasm disassembles an assembly and extracts the CIL generated by the C# compiler into text.
+
+
+
+The output that results from disassembling a .NET assembly is significantly easier to understand than machine code. For many developers, this may raise a concern because it is easier for programs to be decompiled and algorithms understood without explicitly redistributing the source code. As with any program, CLI based or not, the only foolproof way of preventing disassembly is to disallow access to the compiled program altogether (e.g., hosting a program only on a website instead of distributing it to a user’s machine). However, if decreased accessibility to the source code is all that is required, there are several obfuscators available. Obfuscators read the IL code and transform it so that it does the same thing but in a way that is much more difficult to understand. This technique prevents the casual developer from accessing the code and creates assemblies that are much more difficult and tedious to decompile into comprehensible code. Unless a program requires a high degree of algorithm security, obfuscators are generally sufficient.
+
+
+
+
+
AdVanced Topic
+
CIL Output for HelloWorld.exe
+
+
+
+
+
+The exact command used for the CIL disassembler depends on which implementation of the CLI is used. Instructions are available at http://itl.tc/ildasm. Listing 1.22 shows the CIL code created from running Ildasm.
+ 68.
+ } // End of method System.Void HelloWorld.Program::.ctor()
+
+ 69.
+} // End of class HelloWorld.Program
+
+
+
+
+
+
+The beginning of the listing is the manifest information. It includes not only the full name of the disassembled module (HelloWorld.dll) but also all the assemblies it depends on, along with their version information.
+
+
+
+Perhaps the most interesting thing that you can glean from such a listing is how relatively easy it is to follow what the program is doing compared to trying to read and understand machine code (assembler). In the listing, an explicit reference to Console.WriteLine() appears. There is a lot of peripheral information to the CIL code listing, but if a developer wanted to understand the inner workings of a C# assembly (or any CLI-based program) without having access to the original source code, it would be relatively easy unless an obfuscator is used. In fact, several free tools are available (such as Red Gate’s Reflector, ILSpy, JustDecompile, dotPeek, and CodeReflect) that can decompile from CIL to C# automatically.
+
+
+
+
+________________________________________
+
+
+ 14.
+ A third term for CIL is Microsoft IL (MSIL). This book uses the term CIL because it is the term adopted by the CLI standard. IL is prevalent in conversation among people writing C# code because they assume that IL refers to CIL rather than other types of intermediate languages.
+
+
+ 15.
+ Miller, J., and S. Ragsdale. 2004. The Common Language Infrastructure Annotated Standard. Boston: Addison-Wesley.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/06.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/06.html
new file mode 100644
index 00000000..e6ae4e14
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/06.html
@@ -0,0 +1,1835 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Multiple .NET Frameworks
+
+
+
+
+
+As briefly mentioned earlier in the chapter, there are multiple .NET frameworks. The large number of offerings is driven mainly by the desire to provide .NET implementations across multiple operating systems and, potentially, even different hardware platforms. Table 1.3 shows those that are predominant.
+Starting with NET 6 (following .NET Core 5.0), the Core suffix was dropped to indicate .NET Core and the .NET Framework have essentially unified into one framework.
+
+
+
+
+
+
+
+
+
+
+.NET Core
+
+
+
+
+
+
+A truly cross-platform and open source .NET framework that supports a highly modularized set of APIs for both the server and command-line applications.
+
+
+
+
+
+
+
+
+
+
+Microsoft .NET Framework
+
+
+
+
+
+
+The first of the .NET frameworks—slowly being supplanted by .NET.
+
+
+
+
+
+
+
+
+
+
+Xamarin
+
+
+
+
+
+
+With the release of NET 6.0, this effectively becomes a legacy mobile platform implementation of .NET that works with both iOS and Android and enables the development of mobile applications from a single code base while still enabling access to native platform APIs.
+
+
+
+
+
+
+
+
+
+
+Mono
+
+
+
+
+
+
+The oldest open source implementation of .NET that formed the foundation upon which Xamarin and Unity were built. Mono has been replaced by .NET Core for new development.
+
+
+
+
+
+
+
+
+
+
+Unity
+
+
+
+
+
+
+A cross-platform game engine used to develop video games for game consoles, PCs, mobile devices, and even websites. (The Unity engine is the first public implementation to support projections into the Microsoft Hololens augmented reality realm.)
+
+
+
+
+
+
+
+
+
+
+All the samples in the book work for .NET, at a minimum, unless they specifically indicate otherwise.
+
+
+
+
+
+
+
+
+
+
+ note
+
+
+
+
+Throughout the book, .NET framework (lowercase) refers to the framework supported by .NET implementations in general. In contrast, Microsoft .NET Framework refers to the specific .NET framework implementation that runs only on Microsoft Windows and was first released by Microsoft in 2001.
+
+
+
+
+
+
+
+
+
+
+
+Application Programming Interface
+
+
+
+
+
+All the methods (or more generically, the members) found on a data type such as Console are what define the Console’s application programming interface (API). The API defines how a software program interacts with a component. As such, it is found not just with a single data type, but more generically; the combination of all the APIs for a set of data types is said to create an API for the collective set of components. In .NET, for example, all the types (and the members within those types) in an assembly are said to form the assembly’s API. Likewise, given a combination of assemblies, such as those found in .NET, the collective group of assemblies forms a larger API. Often, this larger group of APIs is referred to as the framework—hence the term .NET framework in reference to the APIs exposed by all the assemblies included with the .NET. Generically, the API comprises the set of interfaces and protocols (or instructions) for programming against a set of components. In fact, with .NET, the protocols themselves are the rules for how .NET assemblies execute.
+
+
+
+C# and .NET Versioning
+
+
+
+
+
+Historically, the development life cycle of .NET frameworks has not always been consistent with that of the C# language; therefore, the version of the underlying .NET framework and the corresponding version of the C# language end up with different numbers. This means if you compile with the C# 11.0 compiler, it will, by default, compile against the .NET 7.0, for example. Table 1.4 is a brief overview of the C# and .NET releases for the Microsoft .NET Framework and .NET Core.
+
+
+
+
+
+
+
+
+
+
+
+
+
Table 1.4: C# and .NET Versions
+
+
+
+
+
+
+
+
+
+
+
+Comment Type
+
+
+
+
+
+
+Description
+
+
+
+
+
+
+
+
+
+
+C# 1.0 with Microsoft .NET Framework 1.0/1.1 (Visual Studio 2002 and 2003)
+
+
+
+
+
+
+The initial release of C#. A language built from the ground up to support .NET programming.
+
+
+
+
+
+
+
+
+
+
+C# 2.0 with Microsoft .NET Framework 2.0 (Visual Studio 2005)
+
+
+
+
+
+
+Added generics to the C# language and libraries that supported generics to the Microsoft .NET Framework 2.0.
+
+
+
+
+
+
+
+
+
+
+Microsoft .NET Framework 3.0
+
+
+
+
+
+
+An additional set of APIs for distributed communications (Windows Communication Foundation [WCF]), rich client presentation (Windows Presentation Foundation [WPF]), workflow (Windows Workflow [WF]), and Web authentication (Cardspaces).
+
+
+
+
+
+
+
+
+
+
+C# 3.0 with Microsoft .NET Framework 3.5 (Visual Studio 2008)
+
+
+
+
+
+
+Added support for LINQ, a significant improvement to the APIs used for programming collections. The Microsoft .NET Framework 3.5 provided libraries that extended existing APIs to make LINQ possible.
+
+
+
+
+
+
+
+
+
+
+C# 4.0 with Microsoft .NET Framework 4 (Visual Studio 2010)
+
+
+
+
+
+
+Added support for dynamic typing along with significant improvements in the API for writing multithreaded programs that capitalized on multiple processors and cores within those processors.
+
+
+
+
+
+
+
+
+
+
+C# 5.0 with Microsoft .NET Framework 4.5 (Visual Studio 2012) and WinRT integration
+
+
+
+
+
+
+Added support for asynchronous method invocation without the explicit registration of a delegate callback. An additional change in the framework was support for interoperability with the Windows Runtime (WinRT).
+
+
+
+
+
+
+
+
+
+
+C# 6.0 with Microsoft .NET Framework 4.6 and .NET Core 1.X (Visual Studio 2015)
+
+
+
+
+
+
+Added string interpolation, null propagating member access, exception filters, dictionary initializers, and numerous other features.
+
+
+
+
+
+
+
+
+
+
+C# 7.0 with Microsoft .NET Framework 4.7 and .NET Core 1.1 or 2.0 (Visual Studio 2017)
+
+
+
+
+
+
+Added tuples, deconstructors, pattern matching, local functions, return by reference, and more.
+
+
+
+
+
+
+
+
+
+
+C# 8.0 with Microsoft .NET Framework 4.8 and .NET Core 3.0
+
+
+
+
+
+
+Added support for nullable reference types, advanced pattern matching, using declarations, static local functions, disposable ref structs, ranges and indices, and async streams (although Microsoft .NET Framework 4.8 does not support the last two features).
+
+
+
+
+
+
+
+
+
+
+C# 9.0 with Microsoft .NET 5.0 (most of the .NET Framework functionality was merged into .NET Core)
+
+
+
+
+
+
+Added support for records, relational pattern matching, top-level statements, source generators, and function pointers.
+
+
+
+
+
+
+
+
+
+
+C# 10.0 with .NET 6.0
+
+
+
+
+
+
+Added simplifications included record structs, global using directives, file-scoped namespaces, extended property patterns. In addition, caller argument expressions and more were added.
+
+
+
+
+
+
+
+
+
+
+C# 11 with .NET 7.0
+
+
+
+
+
+
+Added support for file-scoped types, generic math support, default struct initialization, raw literal strings, generic attributes, list patterns, required members, and more.
+
+
+
+
+
+
+
+
+
+
+C# with .NET 8.0
+
+
+
+
+
+
+Extended use of primary constructors beyond records, and the using alias directive to any type. Added optional parameters in lambda expressions, and more.
+
+
+
+
+
+
+
+
+
+
+Perhaps the most important framework feature add occurred alongside C# 6.0—that is, cross-platform compilation. In other words, not only would the Microsoft .NET Framework run on Windows, but Microsoft also provided the .NET Core implementation that would run on Windows, Linux, and macOS. This means that with the same code base it is possible to compile and execute applications that run across multiple platforms. .NET Core, renamed to simply .NET with version 5.0, is an entire SDK with everything from the .NET Compiler Platform (“Roslyn”), which itself executes on Linux and macOS, to the .NET runtime, along with tools such as the dotnet command-line utility, dotnet CLI (which was introduced around the time of C# 7.0).
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/07.html b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/07.html
new file mode 100644
index 00000000..0df4d3fd
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/01/Pages/07.html
@@ -0,0 +1,1241 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Chapter 1: Summary
+
+
+
+
+
+This chapter served as a rudimentary introduction to C#. It provided a means of familiarizing you with basic C# syntax. Because of C#’s similarity to C++-style languages, much of this chapter’s content might not have been new material to you. However, C# and managed code do have some distinct characteristics, such as compilation down to CIL. Although it is not unique, another key characteristic of C# is its full support for object-oriented programming. Even tasks such as reading and writing data to the console are object oriented. Object orientation is foundational to C#, as you will see throughout this book.
+
+
+
+The next chapter examines the fundamental data types that are part of the C# language and discusses how you can use these data types with operands to form expressions.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/02/Pages/01.html b/EssentialCSharp.Web/Placeholders/Chapters/02/Pages/01.html
new file mode 100644
index 00000000..e7593d28
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/02/Pages/01.html
@@ -0,0 +1,1329 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2
+
+
+
+
Data Types
+
+
+
+
+
+From Chapter 1’s HelloWorld program, you got a feel for the C# language, its structure, basic syntax characteristics, and how to write the simplest of programs. This chapter continues to discuss the C# basics by investigating the fundamental C# types.
+
+
+
+
+
+
+
+
+
+
+
+
+Until now, you have worked with only a few built-in data types, with little explanation. In C# thousands of types exist, and you can combine types to create new types. A few types in C#, however, are relatively simple and are considered the building blocks of all other types. These types are the predefined types. The C# language’s predefined types include 10 integer types, two binary floating-point types for scientific calculations and one decimal float for financial calculations, one Boolean type, and a character type. This chapter investigates these types and looks more closely at the string type.
+
+
+
+
+Type Name Forms
+
+
+
+
+
+All built-in types have essentially three name forms. Consider the string type, for example. There is the full name (i.e., System.String), the implied or simplified name (i.e., String), and the keyword (i.e., string).
+
+
+
+The full name provides all the context and disambiguates the type from all other types. This is the name used in the underlying CIL code into which C# compiles. The full name is comprised of the namespace (everything in the fully qualified type’s name before the last period) followed by the type name (the final part of the name after the last period). If it wasn’t for some C# conveniences, all types within C# would be referenced by their full name. All the predefined types themselves are part of the Base Class Library (BCL)—the name given to the set of APIs that comprise the underlying framework. The full name of the types included in the BCL, therefore, is also the BCL name.
+
+
+
+The conveniences are shortcuts that allow the compiler to resolve a type’s namespace implicitly rather than providing the namespace with each reference. Types with long namespaces such as System.Text.RegularExpressions.RegEx benefit a lot from the shortcut of avoiding the namespace qualifier (i.e., RegEx). See “Using Directives” in Chapter 5 for more information about the shortcuts and how the compiler can infer namespaces.
+
+
+
+The keyword is a shortcut built into the C# language specifically for the predefined types. Types that are not predefined don’t have a keyword. Console from Chapter 1, for example, has only the full name (i.e., System.Console) and simpler non-qualified name (Console) with the namespace inferred. Similarly, any of the custom types that you define (such as Program) don’t have a keyword shortcut.
+
+
+
+Developers have a choice of which of the three name forms to use when. Rather than switching back and forth, it is better to use one consistently. While there is seemingly little difference between using the unqualified name versus the keyword, C# developers generally use the C# keyword form (when available)—choosing, for example, string rather than String or System.String and int rather than Int32 or System.Int32. Using the fully qualified name from within C# code is rare and generally reserved to disambiguate types with the same unqualified name (such as System.Timers.Timer and System.Threading.Timer).
+
+
+
+
+
+
+
+Guidelines
+
+
+DO use the C# keyword rather than the unqualified name when specifying a data type (e.g., string rather than String).
+
+DO favor consistency rather than variety within your code.
+
+
+
+
+
+
+The choice for consistency often may be at odds with other guidelines. For example, given the guideline to use the C# keyword in place of the full name, there may be occasions when you find yourself maintaining a file (or library of files) with the opposite style. In these cases, it would be better to stay consistent with the previous style than to inject a new style and inconsistencies in the conventions. Even so, if the “style” was a bad coding practice that was likely to introduce bugs and obstruct successful maintenance, by all means correct the issue throughout.
+
+
+
+
+
+
AdVanced Topic
+
Using Directive and Global Using Static Directive
+
+
+
+
+
+The full name of the Console class that we have used for reading and writing content from the command line is System.Console. The System portion of the name is the namespace. Namespaces provide a hierarchical grouping of types. For example, the RegEx class (used for parsing text with regular expressions) is located in the System.Text.RegularExpressions namespace. Each period in the namespace represents a different level within the hierarchy.
+
+
+
+For example, you can place a using directive at the top of a file, using System, for example, thereby eliminating the need to prefix a type with the namespace because the compiler can assume the namespace from the using directives.
+
+
+
+C# 10 also includes a global using directive such that the using directive is required only once for the entire project, instead of repeatedly within each file that leverages types within the namespace. To identify a using directive as global, you can prefix the statement with global as in global using System.
+
+
+
+In addition, C# 10 generates a default set of global using statements. A lookback at the enable value of the ImplicitUsings element from Listing 1.2 turns this on. Once enabled, it is no longer necessary to provide using directives or fully qualified names for any types in the generated set including System. Specifically, the C# compiler generates a .cs file that contains a set of global using statements.
+
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/Chapters/02/Pages/02.html b/EssentialCSharp.Web/Placeholders/Chapters/02/Pages/02.html
new file mode 100644
index 00000000..b5cb7256
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/Chapters/02/Pages/02.html
@@ -0,0 +1,3144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Fundamental Numeric Types
+
+
+
+
+
+The basic numeric types in C# have keywords associated with them. These types include integer types, floating-point types, and a special floating-point type called decimal to store large numbers with no representation error.
+
+
+
+
+Integer Types
+
+
+
+
+
+There are 10 C# integer types, as shown in Table 2.1. This variety allows you to select a data type large enough to hold its intended range of values without wasting resources.
+
+
+
Table 2.1: Integer Types
+
+
+
+
+
+
+
+
+
+
+
+Type
+
+
+
+
+
+
+Size
+
+
+
+
+
+
+Range (Inclusive)
+
+
+
+
+
+
+BCL Name
+
+
+
+
+
+
+Signed
+
+
+
+
+
+
+Literal Suffix
+
+
+
+
+
+
+
+
+
+
+sbyte
+
+
+
+
+
+
+8 bits
+
+
+
+
+
+
+–128 to 127
+
+
+
+
+
+
+System.SByte
+
+
+
+
+
+
+Yes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+byte
+
+
+
+
+
+
+8 bits
+
+
+
+
+
+
+0 to 255
+
+
+
+
+
+
+System.Byte
+
+
+
+
+
+
+No
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+short
+
+
+
+
+
+
+16 bits
+
+
+
+
+
+
+–32,768 to 32,767
+
+
+
+
+
+
+System.Int16
+
+
+
+
+
+
+Yes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ushort
+
+
+
+
+
+
+16 bits
+
+
+
+
+
+
+0 to 65,535
+
+
+
+
+
+
+System.UInt16
+
+
+
+
+
+
+No
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int
+
+
+
+
+
+
+32 bits
+
+
+
+
+
+
+–2,147,483,648 to 2,147,483,647
+
+
+
+
+
+
+System.Int32
+
+
+
+
+
+
+Yes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+uint
+
+
+
+
+
+
+32 bits
+
+
+
+
+
+
+0 to 4,294,967,295
+
+
+
+
+
+
+System.UInt32
+
+
+
+
+
+
+No
+
+
+
+
+
+
+U or u
+
+
+
+
+
+
+
+
+
+
+Long
+
+
+
+
+
+
+64 bits
+
+
+
+
+
+
+–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
+
+
+
+
+
+
+System.Int64
+
+
+
+
+
+
+Yes
+
+
+
+
+
+
+L or l
+
+
+
+
+
+
+
+
+
+
+ulong
+
+
+
+
+
+
+64 bits
+
+
+
+
+
+
+0 to 18,446,744,073,709,551,615
+
+
+
+
+
+
+System.UInt64
+
+
+
+
+
+
+No
+
+
+
+
+
+
+UL or ul
+
+
+
+
+
+
+
+
+
+
+nint
+
+
+
+
+
+
+Signed 32-bit or 64-bit integer is a [depends on platform]
+
+
+
+
+
+
+Depends on platform where the code is executing.
+
+
+
+Use sizeof(nint) to retrieve size.
+
+
+
+
+
+
+System.IntPtr
+
+
+
+
+
+
+Yes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+nuint
+
+
+
+
+
+
+Unsigned 32-bit or 64-bit integer is a [depends on platform]
+
+
+
+
+
+
+Depends on platform where the code is executing.
+
+
+
+Use sizeof(nuint) to retrieve size.
+
+
+
+
+
+
+System.UIntPtr
+
+
+
+
+
+
+No
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Included in Table 2.1 (and all the type tables within this section) is a column for the full name of each type; we discuss the literal suffix later in the chapter. All the fundamental types in C# have both a short name and a full name. The full name corresponds to the type as it is named in the BCL. This name, which is the same across all languages, uniquely identifies the type within an assembly. Because of the fundamental nature of these types, C# also supplies keywords as short names or abbreviations for the full names of fundamental types. From the compiler’s perspective, both names refer to the same type, producing identical code. In fact, an examination of the resultant Common Intermediate Language (CIL) code would provide no indication of which name was used.
+
+
+
+
+
+
+
+Language Contrast: C++—short Data Type
+
+
+
+
+
+
+
+In C/C++, the short data type is an abbreviation for short int. In C#, short on its own is the actual data type.
+
+
+
+
+
+
+
+Floating-Point Types (float, double)
+
+
+
+
+
+Floating-point numbers have varying degrees of precision, and binary floating-point types can represent numbers exactly only if they are a fraction with a power of 2 as the denominator. If you were to set the value of a floating-point variable to be 0.1, it could very easily be represented as 0.0999999999999999 or 0.10000000000000001 or some other number very close to 0.1. Similarly, setting a variable to a large number such as Avogadro’s number, 6.02 × 1023, could lead to a representation error of approximately 108, which after all is a tiny fraction of that number. The accuracy of a floating-point number is in proportion to the magnitude of the number it represents. A floating-point number is precise to a certain number of digits of precision, not by a fixed value such as ±0.01. There are at most 17 significant digits for a double and 9 significant digits for a float1 (assuming the number wasn’t converted from a string as described in the “Advanced Topic: Floating-Point Types Dissected”). 2
+
+
+
+C# supports the two binary floating-point number types listed in Table 2.2. Binary numbers appear as base 10 (denary) numbers for human readability. While there are additional floating-point types beyond the scope of this book (see https://learn.microsoft.com/dotnet/standard/numerics), they are not built-in types with associated keywords.
+
+
+
Table 2.2: Floating-Point Types
+
+
+
+
+
+
+
+
+
+
+
+Type
+
+
+
+
+
+
+Size
+
+
+
+
+
+
+Significant Digits
+
+
+
+
+
+
+BCL Name
+
+
+
+
+
+
+Significant Digits
+
+
+
+
+
+
+Literal Suffix
+
+
+
+
+
+
+
+
+
+
+float
+
+
+
+
+
+
+32 bits
+
+
+
+
+
+
+±1.5 × 10−45 to ±3.4 × 1038
+
+
+
+
+
+
+System.Single
+
+
+
+
+
+
+7
+
+
+
+
+
+
+F or f
+
+
+
+
+
+
+
+
+
+
+double
+
+
+
+
+
+
+64 bits
+
+
+
+
+
+
+±5.0 × 10−324 to ±1.7 × 10308
+
+
+
+
+
+
+System.Double
+
+
+
+
+
+
+15–16
+
+
+
+
+
+
+D or d
+
+
+
+
+
+
+
+
+
+
+
+
+
AdVanced Topic
+
Floating-Point Types Dissected
+
+
+
+
+
+
+Denary numbers within the range and precision limits of the decimal type are represented exactly. In contrast, the binary floating-point representation of many denary numbers introduces a rounding error. Just as ⅓ cannot be represented exactly in any finite number of decimal digits, so ¹¹⁄₁₀ cannot be represented exactly in any finite number of binary digits (the binary representation being 1.0001100110011001101…). In both cases, we end up with a rounding error of some kind.
+
+
+
+A decimal is represented by ±N * 10k where the following is true:
+
+
+
+
+
+ •
+
+
+
+N, the mantissa, is a positive 96-bit integer.
+
+
+
+
+
+ •
+
+
+
+k, the exponent, is given by -28 <= k <= 0.
+
+
+
+
+
+
+In contrast, a binary float is any number ±N * 2k where the following is true:
+
+
+
+
+
+ •
+
+
+
+N is a positive 24-bit (for float) or 53-bit (for double) integer.
+
+
+
+
+
+ •
+
+
+
+k is an integer ranging from -149 to +104 for float and from -1074 to +970 for double.
+
+
+
+
+
+
+Decimal Type
+
+
+
+
+
+C# also provides a decimal floating-point type with 128-bit precision (see Table 2.3). This type is suitable for financial calculations.
+
+
+
Table 2.3: Decimal Type
+
+
+
+
+
+
+
+
+
+
+
+Type
+
+
+
+
+
+
+Size
+
+
+
+
+
+
+Range (Inclusive)
+
+
+
+
+
+
+BCL Name
+
+
+
+
+
+
+Significant Digits
+
+
+
+
+
+
+Literal Suffix
+
+
+
+
+
+
+
+
+
+
+decimal
+
+
+
+
+
+
+128 bits
+
+
+
+
+
+
+1.0 × 10−28 to approximately 7.9 × 1028
+
+
+
+
+
+
+System.Decimal
+
+
+
+
+
+
+28–29
+
+
+
+
+
+
+M or m
+
+
+
+
+
+
+Unlike binary floating-point numbers, the decimal type maintains exact accuracy for all denary numbers within its range. With the decimal type, therefore, a value of 0.1 is exactly 0.1. However, while the decimal type has greater precision than the floating-point types, it has a smaller range. Thus, conversions from floating-point types to the decimal type may result in overflow errors. Also, calculations with decimal are slightly (generally imperceptibly) slower.
+
+
+
+
+
+
+
AdVanced Topic
+
Native-Sized Integers
+
+
+
+
+
+C# 9.0 added new contextual keywords to represent native-sized signed and unsigned integers, specifically nint and nuint respectively starting in C# 11. (See Table 2.4.) Unlike the other numeric types that are the same size regardless of the underlying operating system, the native sized integer types will vary depending on what platform the code is executing. A nint, for example, will be 32-bits on a 32-bit platform and 64-bit on a 64-bit platform. These types are designed to match the size of a pointer within the system on which they are executing. They are a more advanced type because they are generally only useful when working with pointers and memory in the underlying operating system rather than memory within the managed execution context of .NET.
+
+
+
Table 2.4: Native Integer Types3
+
+
+
+
+
+
+
+
+
+
+
+Type
+
+
+
+
+
+
+Size
+
+
+
+
+
+
+Range (Inclusive)
+
+
+
+
+
+
+BCL Name
+
+
+
+
+
+
+Significant Digits
+
+
+
+
+
+
+Literal Suffix
+
+
+
+
+
+
+
+
+
+
+nint
+
+
+
+
+
+
+Matches Operating System (OS)
+
+
+
+
+
+
+Variable but available at runtime via nint.MinValue and nint.MaxValue
+
+
+
+
+
+
+System.IntPtr
+
+
+
+
+
+
+Matches OS
+
+
+
+
+
+
+none
+
+
+
+
+
+
+
+
+
+
+nuint
+
+
+
+
+
+
+Matches Operating System (OS)
+
+
+
+
+
+
+Variable but available at runtime via unint.MinValue and unint.MaxValue
+
+
+
+
+
+
+System.UIntPtr
+
+
+
+
+
+
+Matches OS
+
+
+
+
+
+
+none
+
+
+
+
+
+
+See Chapter 23 for more information on nint and nuint.
+
+
+
+
+
+Literal Values
+
+
+
+
+
+A literal value is a representation of a constant value within source code. For example, if you want to have Console.WriteLine() print out the integer value 42 and the double value 1.618034, you could use the code shown in Listing 2.1 with Output 2.1.
+
+
+
+
+Listing 2.1: Specifying Literal Values
+
+
+
+ 1.
+Console.WriteLine(42);
+
+ 2.
+
+
+ 3.
+Console.WriteLine(1.618034);
+
+
+
+
+
+
+
+
+
+
+
+Output 2.1
+
+
+
+42
+
+1.618034
+
+
+
+
+
+
+
+
+
Beginner Topic
+
Use Caution When Hardcoding Values
+
+
+
+
+
+The practice of placing a value directly into source code is called hardcoding, because changing the values requires recompiling the code. Developers must carefully consider the choice between hardcoding values within their code and retrieving them from an external source, such as a configuration file, so that the values are modifiable without recompiling.
+
+
+
+By default, when you specify a literal number with a decimal point, the compiler interprets it as a double type. Conversely, a literal value with no decimal point generally defaults to an int, assuming the value is not too large to be stored in a 32-bit integer. If the value is too large, the compiler interprets it as a long. Furthermore, the C# compiler allows assignment to a numeric type other than an int, assuming the literal value is appropriate for the target data type. short s = 42 and byte b = 77 are allowed, for example. However, this is appropriate only for constant values; b = s is not allowed without additional syntax, as discussed in the section “Conversions between Data Types” later in this chapter.
+
+
+
+As previously discussed in this section, there are many different numeric types in C#. In Listing 2.2, a literal value is passed to the WriteLine method. Since numbers with a decimal point will default to the double data type, the output, shown in Output 2.2, is 1.618033988749895 (the last two digits, 48, are now 5), corresponding to the expected accuracy of a double.
+
+
+
+
+Listing 2.2: Specifying a Literal double
+
+
+
+ 1.
+Console.WriteLine(1.6180339887498948);
+
+
+
+
+
+
+
+Output 2.2
+
+
+
+1.618033988749895
+
+
+
+
+
+
+
+
+
+
+
+To view the intended number with its full accuracy, you must declare explicitly the literal value as a decimal type by appending an M (or m) (see Listing 2.3 and Output 2.3).
+
+
+
+
+Listing 2.3: Specifying a Literal decimal
+
+
+
+ 1.
+Console.WriteLine(1.6180339887498948M);
+
+
+
+
+
+
+
+Output 2.3
+
+
+
+1.6180339887498948
+
+
+
+
+
+
+
+
+
+
+
+
+
+Now the output of Listing 2.3 is as expected: 1.618033988749895. Note that d is the abbreviation for double. To remember that M should be used to identify a decimal, remember that “m is for monetary calculations.”
+
+
+
+You can also add a suffix to a value to explicitly declare a literal as a float or double by using the F (or f) and D (or d) suffixes, respectively. For integer data types, the suffixes are U, L, LU, and UL. The type of an integer literal can be determined as follows:
+
+
+
+
+
+ •
+
+
+
+Numeric literals with no suffix resolve to the first data type that can store the value, in this order: int, uint, long, and ulong.
+
+
+
+
+
+ •
+
+
+
+Numeric literals with the suffix U resolve to the first data type that can store the value, in the order uint and then ulong.
+
+
+
+
+
+ •
+
+
+
+Numeric literals with the suffix L resolve to the first data type that can store the value, in the order long and then ulong.
+
+
+
+
+
+ •
+
+
+
+If the numeric literal has the suffix UL or LU, it is of type ulong.
+
+
+
+
+
+
+Note that suffixes for literals are case insensitive. However, uppercase is generally preferred to avoid any ambiguity between the lowercase letter l and the digit 1.
+
+
+
+
+
+
+
+Guidelines
+
+
+DO use uppercase literal suffixes (e.g., 1.618033988749895M).
+
+
+
+
+
+
+
+On occasion, numbers can get quite large and difficult to read. To overcome the readability problem, C# 7.0 added support for a digit separator, an underscore (_), when expressing a numeric literal, as shown in Listing 2.4.
+
+
+
+
+Listing 2.4: Specifying Digit Separator
+
+
+
+ 1.
+Console.WriteLine(9_814_072_356M);
+
+
+
+
+
+
+In this case, we separate the digits into thousands (threes), but this is not required by C#. You can use the digit separator to create whatever grouping you like as long as the underscore occurs between the first and last digits. In fact, you can even have multiple underscores side by side—with no digit between them.
+
+
+
+
+In addition, you may wish to use exponential notation instead of writing out several zeroes before or after the decimal point (whether using a digit separator or not). To use exponential notation, supply the e or E infix, follow the infix character with a positive or negative integer number, and complete the literal with the appropriate data type suffix. For example, you could print out Avogadro’s number as a float, as shown in Listing 2.5 and Output 2.4.
+
+
+
+
+Listing 2.5: Exponential Notation
+
+
+
+ 1.
+Console.WriteLine(6.023E23F);
+
+
+
+
+
+
+
+Output 2.4
+
+
+
+6.023E+23
+
+
+
+
+
+
+
+
+
Beginner Topic
+
Hexadecimal Notation
+
+
+
+
+
+Usually, you work with numbers that are represented with a base of 10, meaning there are 10 symbols (0–9) for each place value in the number. If a number is displayed with hexadecimal notation, it is displayed with a base of 16 numbers, meaning 16 symbols are used: 0–9, A–F (or in lowercase). Therefore, 0x000A corresponds to the decimal value 10 and 0x002A corresponds to the decimal value 42, being 2 × 16 + 10. The actual number is the same. Switching from hexadecimal to decimal, or vice versa, does not change the number itself—just the representation of the number.
+
+
+
+Each hex digit is four bits, so a byte can represent two hex digits.
+
+
+
+In all discussions of literal numeric values so far, we have covered only base 10 type values. C# also supports the ability to specify hexadecimal values. To specify a hexadecimal value, prefix the value with 0x and then use any hexadecimal series of digits, as shown in Listing 2.6.
+
+
+
+
+Listing 2.6: Hexadecimal Literal Value
+
+
+
+ 1.
+//Display the value 42 using a hexadecimal literal
+
+ 2.
+Console.WriteLine(0x002A);
+
+
+
+
+
+
+Output 2.5 shows the results of Listing 2.6. Note that this code still displays 42, not 0x002A.
+
+
+
+
+Output 2.5
+
+
+
+42
+
+
+
+
+
+
+
+
+Starting with C# 7.0, you can also represent numbers as binary values (see Listing 2.7).
+
+
+
+
+Listing 2.7: Binary Literal Value
+
+
+
+ 1.
+// Display the value 42 using a binary literal
+
+ 2.
+Console.WriteLine(0b101010);
+
+
+
+
+
+
+The syntax is like the hexadecimal syntax except with 0b as the prefix (an uppercase B is also allowed). See “Beginner Topic: Bits and Bytes” in Chapter 4 for an explanation of binary notation and the conversion between binary and decimal.
+
+
+
+Note that starting with C# 7.2, you can place the digit separator after the x for a hexadecimal literal or the b for a binary literal.
+
+
+
+
+
+
AdVanced Topic
+
Formatting Numbers as Hexadecimal
+
+
+
+
+
+To display a numeric value in its hexadecimal format, it is necessary to use the x or X numeric formatting specifier. The casing determines whether the hexadecimal letters appear in lowercase or uppercase. Listing 2.8 with Output 2.6 shows an example of how to do this.
+
+
+
+
+Listing 2.8: Example of a Hexadecimal Format Specifier
+
+
+
+ 1.
+//Displays "0x2A"
+
+ 2.
+Console.WriteLine($"0x{42:X}");
+
+
+
+
+
+
+
+Output 2.6
+
+
+
+0x2A
+
+
+
+
+
+
+
+Note that the numeric literal (42) can be in decimal or hexadecimal form. The result will be the same. Also, to achieve the hexadecimal formatting, we rely on the formatting specifier, separated from the string interpolation expression with a colon.
+
+
+
+
+
AdVanced Topic
+
Round-Trip Formatting
+
+
+
+
+
+By default, Console.WriteLine(1.618033988749895); displays 1.61803398874989, with the last digit missing. To more accurately identify the string representation of the double value, it is possible to convert it using a format string and the round-trip format specifier, R (or r). For example, Console.WriteLine($"{1.618033988749895:R}") will display 1.6180339887498949.
+
+
+
+The round-trip format specifier returns a string that, if converted back into a numeric value, will always result in the original value. Listing 2.9 with Output 2.7 shows the numbers are not equal without the use of the round-trip format.
+
+
+
+
+Listing 2.9: Formatting Using the R Format Specifier
+When assigning text the first time, there is no round-trip format specifier; as a result, the value returned by double.Parse(text) is not the same as the original number value. In contrast, when the round-trip format specifier is used, double.Parse(text) returns the original value.
+
+
+
+For those readers who are unfamiliar with the == syntax from C-based languages, result== number evaluates to true if result is equal to number, while result !=number does the opposite. Both assignment and equality operators are discussed in the next chapter.
+
+
+
+________________________________________
+
+
+ 1.
+ Starting with .NET Core 3.0.
+
+
+ 2.
+ Prior to .NET Core 3.0, the number of bits (binary digits) converts to 15 decimal digits, with a remainder that contributes to a sixteenth decimal digit as expressed in Table 2.2. Specifically, numbers between 1.7 × 10307 and less than 1 × 10308 have only 15 significant digits. However, numbers ranging from 1 × 10308 to 1.7 × 10308 will have 16 significant digits. A similar range of significant digits occurs with the decimal type as well.
+
+
+ 3.
+ The exact BCL type varies based on context.
+
+
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/guidelines.json b/EssentialCSharp.Web/Placeholders/guidelines.json
new file mode 100644
index 00000000..1fa7badc
--- /dev/null
+++ b/EssentialCSharp.Web/Placeholders/guidelines.json
@@ -0,0 +1,1930 @@
+[
+ {
+ "Type": 1,
+ "Guideline": "DO NOT define a struct unless it logically represents a single value, consumes 16 bytes or less of storage, is immutable, and is infrequently boxed.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": ""
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use record struct when declaring a struct (C# 10.0).",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Structs",
+ "ActualSubsection": "Record Struct Code Generation"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use record class (C# 10.0) for clarity, rather than the abbreviated record-only syntax.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Structs",
+ "ActualSubsection": "Record Struct Code Generation"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use records, where possible, if you want equality based on data rather than identity.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Classes",
+ "ActualSubsection": "Record Classes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use PascalCase for the positional parameters of the record (C# 9.0).",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Data Storage with Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO define all reference type positional parameters as nullable if not providing a custom property implementation that checks for null.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Data Storage with Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement custom non-nullable properties for all non-nullable positional parameters.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Data Storage with Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the readonly modifier on a struct definition, making value types immutable.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Immutable Value Types"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use read-only or init-only setter automatically implemented properties rather than fields within structs.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Immutable Value Types"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO ensure that the default value of a struct is valid; encapsulation cannot prevent obtaining the default \u201Call zero\u201D value of a struct.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Structs",
+ "ActualSubsection": "Record Struct Initialization"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT rely on either default constructors or member initialization at declaration to run on a value type.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Structs",
+ "ActualSubsection": "Record Struct Initialization"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO override ToString() whenever useful developer-oriented diagnostic strings can be returned.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "ToString()",
+ "ActualSubsection": "Overriding ToString()"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER trying to keep the string returned from ToString() short.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "ToString()",
+ "ActualSubsection": "Overriding ToString()"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT return an empty string or null from ToString().",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "ToString()",
+ "ActualSubsection": "Overriding ToString()"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT throw exceptions or make observable side effects (change the object state) from ToString().",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "ToString()",
+ "ActualSubsection": "Overriding ToString()"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide an overloaded ToString(string format) or implement IFormattable if the return value requires formatting or is culture-sensitive (e.g., DateTime).",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "ToString()",
+ "ActualSubsection": "Overriding ToString()"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER returning a unique string from ToString() so as to identify the object instance.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "ToString()",
+ "ActualSubsection": "Overriding ToString()"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use the enum type name as part of the values name.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use an enum type name that is singular unless the enum is a flag.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using the default 32-bit integer type as the underlying type of an enum. Use a smaller type only if you must do so for interoperability; use a larger type only if you are creating a flags enum with more than 32 flags.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER adding new members to existing enums, but keep in mind the compatibility risk.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID creating enums that represent an \u201Cincomplete\u201D set of values, such as product version numbers.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID creating \u201Creserved for future use\u201D values in an enum.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID enums that contain a single value.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide a value of 0 (none) for simple enums, knowing that 0 will be the default value when no explicit initialization is provided.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID direct enum/string conversions where the string must be localized into the user\u2019s language.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Converting between Enums and Strings"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the FlagsAttribute to mark enums that contain flag values.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums as Flags"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide a None value equal to 0 for all enums.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums as Flags"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID creating flag enums where the zero value has a meaning other than \u201Cno flags are set.\u201D",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums as Flags"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER providing special values for commonly used combinations of flags.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums as Flags"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT include \u201Csentinel\u201D values (such as a value called Maximum); such values can be confusing to the user.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums as Flags"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use powers of 2 to ensure that all flag combinations are represented uniquely.",
+ "ChapterNumber": 9,
+ "ChapterTitle": "Introducing Structs and Records",
+ "SanitizedSubsection": "Enums",
+ "ActualSubsection": "Enums as Flags"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO check that the value of a delegate is not null before invoking it.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Check for null"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the null-conditional operator prior to calling Invoke() starting in C# 6.0.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Check for null"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO check that the value of a delegate is not null before invoking it (possibly by using the null-conditional operator in C# 6.0).",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Coding Conventions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO pass the instance of the class as the value of the sender for nonstatic events.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Coding Conventions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO pass null as the sender for static events.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Coding Conventions"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT pass null as the value of the eventArgs argument.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Coding Conventions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use System.EventArgs or a type that derives from System.EventArgs for a TEventArgs type.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Coding Conventions"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using a subclass of System.EventArgs as the event argument type (TEventArgs) unless you are sure the event will never need to carry any data.",
+ "ChapterNumber": 14,
+ "ChapterTitle": "Events",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Coding Conventions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO throw an ArgumentException or one of its subtypes if bad arguments are passed to a member. Prefer the most derived exception type (e.g., ArgumentNullException), if applicable.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Multiple Exception Types"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT throw a System.SystemException or an exception type that derives from it.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Multiple Exception Types"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT throw a System.Exception, System.NullReferenceException, or System.ApplicationException.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Multiple Exception Types"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER terminating the process by calling System.Environment.FailFast() if the program encounters a scenario where it is unsafe to continue execution.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Multiple Exception Types"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use nameof for the paramName argument passed into argument exception types that take such a parameter. Examples of such exceptions include ArgumentException, ArgumentOutOfRangeException, and ArgumentNullException.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Multiple Exception Types"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID exception reporting or logging lower in the call stack.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT over-catch. Exceptions should be allowed to propagate up the call stack unless it is clearly understood how to programmatically address those errors lower in the stack.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER catching a specific exception when you understand why it was thrown in a given context and can respond to the failure programmatically.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID catching System.Exception or System.SystemException except in top-level exception handlers that perform final cleanup operations before rethrowing the exception.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use throw; rather than throw \u003Cexception object\u003E inside a catch block.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use exception filters to avoid rethrowing an exception from within a catch block.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use caution when rethrowing different exceptions.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID throwing exceptions from exception filters.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID exception filters with logic that might implicitly change over time.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Guidelines for Exception Handling"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID deep exception hierarchies.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT create a new exception type if the exception would not be handled differently than an existing CLR exception. Throw the existing framework exception instead.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO create a new exception type to communicate a unique program error that cannot be communicated using an existing CLR exception and that can be programmatically handled in a different way than any other existing CLR exception type.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide a parameterless constructor on all custom exception types. Also provide constructors that take a message and an inner exception.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO name exception classes with the \u201CException\u201D suffix.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO make exceptions runtime-serializable.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER providing exception properties for programmatic access to extra information relevant to the exception.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Defining Custom Exceptions"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER wrapping specific exceptions thrown from the lower layer in a more appropriate exception if the lower-layer exception does not make sense in the context of the higher-layer operation.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Rethrowing a Wrapped Exception"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO specify the inner exception when wrapping exceptions.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Rethrowing a Wrapped Exception"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO target developers as the audience for exceptions, identifying both the problem and the mechanism to resolve it, where possible.",
+ "ChapterNumber": 11,
+ "ChapterTitle": "Exception Handling",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Rethrowing a Wrapped Exception"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO create public managed wrappers around unmanaged methods that use the conventions of managed code, such as structured exception handling.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Error Handling"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT unnecessarily replicate existing managed classes that already perform the function of the unmanaged API.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO declare extern methods as private or internal.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide public wrapper methods that use managed conventions such as structured exception handling, use of enums for special values, and so on.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO simplify the wrapper methods by choosing default values for unnecessary parameters.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the SetLastErrorAttribute on Windows to turn APIs that use SetLastError error codes into methods that throw Win32Exception.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO extend SafeHandle or implement IDisposable and create a finalizer to ensure that unmanaged resources can be cleaned up effectively.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use delegate types that match the signature of the desired method when an unmanaged API requires a function pointer.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use ref parameters rather than pointer types when possible.",
+ "ChapterNumber": 23,
+ "ChapterTitle": "Platform Interoperability and Unsafe Code",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "P/Invoke Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO ensure that custom comparison logic produces a consistent \u201Ctotal order.\u201D",
+ "ChapterNumber": 17,
+ "ChapterTitle": "Building Custom Collections",
+ "SanitizedSubsection": "Equality",
+ "ActualSubsection": "Total Ordering"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT make any unwarranted assumptions about the order in which elements of a collection will be enumerated. If the collection is not documented as enumerating its elements in a particular order, it is not guaranteed to produce elements in any particular order.",
+ "ChapterNumber": 17,
+ "ChapterTitle": "Building Custom Collections",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Dictionary Collections: Dictionary\u003CTKey, TValue\u003E"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT represent an empty collection with a null reference.",
+ "ChapterNumber": 17,
+ "ChapterTitle": "Building Custom Collections",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Returning null or an Empty Collection"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using the Enumerable.Empty\u003CT\u003E() method instead.",
+ "ChapterNumber": 17,
+ "ChapterTitle": "Building Custom Collections",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Returning null or an Empty Collection"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER whether the readability benefit of defining your own delegate type outweighs the convenience of using a predefined generic delegate type.",
+ "ChapterNumber": 13,
+ "ChapterTitle": "Delegates and Lambda Expressions",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "General-Purpose Delegate Types: System.Func and System.Action"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER omitting the types from lambda formal parameter lists when the types are obvious to the reader or when they are an insignificant detail.",
+ "ChapterNumber": 13,
+ "ChapterTitle": "Delegates and Lambda Expressions",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Statement Lambdas"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID the anonymous method syntax in new code; prefer the more compact lambda expression syntax.",
+ "ChapterNumber": 13,
+ "ChapterTitle": "Delegates and Lambda Expressions",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Anonymous Methods"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID using implicitly typed local variables (var) unless the data type of the assigned value is obvious.",
+ "ChapterNumber": 3,
+ "ChapterTitle": "More with Data Types",
+ "SanitizedSubsection": "Variables",
+ "ActualSubsection": "Implicitly Typed Local Variables"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use camelCasing for variable declarations using tuple syntax.",
+ "ChapterNumber": 3,
+ "ChapterTitle": "More with Data Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Tuples"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using PascalCasing for all tuple item names.",
+ "ChapterNumber": 3,
+ "ChapterTitle": "More with Data Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Tuples"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER checking the array length before indexing into an array rather than assuming the length.",
+ "ChapterNumber": 3,
+ "ChapterTitle": "More with Data Types",
+ "SanitizedSubsection": "Arrays",
+ "ActualSubsection": "Using an Array"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using the index from end operator (^) rather than Length - 1 with C# 8.0 or higher.",
+ "ChapterNumber": 3,
+ "ChapterTitle": "More with Data Types",
+ "SanitizedSubsection": "Arrays",
+ "ActualSubsection": "Using an Array"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use System.Linq.Enumerable.Any() rather than calling patents.Count() when checking whether there are more than zero items.",
+ "ChapterNumber": 15,
+ "ChapterTitle": "Collection Interfaces with Standard Query Operators",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Counting Elements with Count()"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use a collection\u2019s Count property (if available) instead of calling the System.Linq.Enumerable.Count() method.",
+ "ChapterNumber": 15,
+ "ChapterTitle": "Collection Interfaces with Standard Query Operators",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Counting Elements with Count()"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT call an OrderBy() following a prior OrderBy() method call. Use ThenBy() to sequence items by more than one value.",
+ "ChapterNumber": 15,
+ "ChapterTitle": "Collection Interfaces with Standard Query Operators",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Sorting with OrderBy() and ThenBy()"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO cancel unfinished tasks rather than allowing them to run during application shutdown.",
+ "ChapterNumber": 19,
+ "ChapterTitle": "Introducing Multithreading",
+ "SanitizedSubsection": "Tasks",
+ "ActualSubsection": "Canceling a Task"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO inform the task factory that a newly created task is likely to be long-running so that it can manage it appropriately.",
+ "ChapterNumber": 19,
+ "ChapterTitle": "Introducing Multithreading",
+ "SanitizedSubsection": "Tasks",
+ "ActualSubsection": "Long-Running Tasks"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use TaskCreationOptions.LongRunning sparingly.",
+ "ChapterNumber": 19,
+ "ChapterTitle": "Introducing Multithreading",
+ "SanitizedSubsection": "Tasks",
+ "ActualSubsection": "Long-Running Tasks"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID calling Thread.Sleep() in production code.",
+ "ChapterNumber": 19,
+ "ChapterTitle": "Introducing Multithreading",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Working with System.Threading"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use tasks and related APIs in favor of System.Theading classes such as Thread and ThreadPool.",
+ "ChapterNumber": 19,
+ "ChapterTitle": "Introducing Multithreading",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Working with System.Threading"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use PascalCasing and an \u201CI\u201D prefix for interface names.",
+ "ChapterNumber": 8,
+ "ChapterTitle": "Interfaces",
+ "SanitizedSubsection": "Interfaces",
+ "ActualSubsection": "Introducing Interfaces"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT add members without a default implementation to a published interface.",
+ "ChapterNumber": 8,
+ "ChapterTitle": "Interfaces",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Versioning"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using extension methods or an additional interface in place of default interface members when adding methods to a published interface.",
+ "ChapterNumber": 8,
+ "ChapterTitle": "Interfaces",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Extension Methods versus Default Interface Members"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use extension methods when the interface providing the polymorphic behavior is not under your control.",
+ "ChapterNumber": 8,
+ "ChapterTitle": "Interfaces",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Extension Methods versus Default Interface Members"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER defining an interface if you need to support its functionality on types that already inherit from some other type.",
+ "ChapterNumber": 8,
+ "ChapterTitle": "Interfaces",
+ "SanitizedSubsection": "Interfaces",
+ "ActualSubsection": "Interfaces Compared with Abstract Classes"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID using \u201Cmarker\u201D interfaces with no members; use attributes instead.",
+ "ChapterNumber": 8,
+ "ChapterTitle": "Interfaces",
+ "SanitizedSubsection": "Interfaces",
+ "ActualSubsection": "Interfaces Compared with Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor clarity over brevity when naming identifiers.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Identifiers"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use abbreviations or contractions within identifier names.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Identifiers"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use any acronyms unless they are widely accepted, in which case use them consistently.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Identifiers"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO capitalize both characters in two-character acronyms, except for the first word of a camelCased identifier.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO capitalize only the first character in acronyms with three or more characters, except for the first word of a camelCased identifier.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT capitalize any of the characters in acronyms at the beginning of a camelCased identifier.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use Hungarian notation (that is, do not encode the type of a variable in its name).",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO name classes with nouns or noun phrases.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Type Definition"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use PascalCasing for all class names.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Type Definition"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use camelCasing for local variable names.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Variables",
+ "ActualSubsection": "Declaring a Variable"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use comments unless they describe something that is not obvious to someone other than the developer who wrote the code.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Comments",
+ "ActualSubsection": "Comments"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor writing clearer code over entering comments to clarify a complicated algorithm.",
+ "ChapterNumber": 1,
+ "ChapterTitle": "Introducing C#",
+ "SanitizedSubsection": "Comments",
+ "ActualSubsection": "Comments"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID locking on this, System.Type, or a string.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Why to Avoid Locking on this, typeof(type), and string"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO declare a separate, read-only synchronization variable of type object for the synchronization target.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Why to Avoid Locking on this, typeof(type), and string"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID using the MethodImplAttribute for synchronization.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Synchronization",
+ "ActualSubsection": "Avoid Synchronizing with MethodImplAttribute"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT request exclusive ownership of the same two or more synchronization targets in different orders.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Avoiding Unnecessary Locking"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO ensure that code that concurrently holds multiple locks always acquires them in the same order.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Avoiding Unnecessary Locking"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO encapsulate mutable static data in public APIs with synchronization logic.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Avoiding Unnecessary Locking"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID synchronization on simple reading or writing of values no bigger than a native (pointer-size) integer, as such operations are automatically atomic.",
+ "ChapterNumber": 22,
+ "ChapterTitle": "Thread Synchronization",
+ "SanitizedSubsection": "Threads",
+ "ActualSubsection": "Avoiding Unnecessary Locking"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO apply AssemblyVersionAttribute to assemblies with public types.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Attributes"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER applying AssemblyFileVersionAttribute and AssemblyCopyrightAttribute to provide additional information about the assembly.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO apply the following information assembly attributes: System.Reflection.AssemblyCompanyAttribute, System.Reflection.AssemblyCopyrightAttribute, System.Reflection.AssemblyDescriptionAttribute, and System.Reflection.AssemblyProductAttribute.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO name custom attribute classes with the suffix Attribute.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Custom Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide get-only properties (without public setters) on attributes with required property values.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Initializing an Attribute through a Constructor"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide constructor parameters to initialize properties on attributes with required properties. Each parameter should have the same name (albeit with different casing) as the corresponding property.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Initializing an Attribute through a Constructor"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID providing constructor parameters to initialize attribute properties corresponding to the optional arguments (and, therefore, avoid overloading custom attribute constructors).",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Initializing an Attribute through a Constructor"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO apply the AttributeUsageAttribute class to custom attributes.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "System.AttributeUsageAttribute"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT explicitly pass arguments for Caller* attribute decorated parameters.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Caller* Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use non-nullable string for the data type of Caller* attribute decorated string parameters.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Caller* Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO assign null! for the default value of Caller* attribute decorated string parameters.",
+ "ChapterNumber": 18,
+ "ChapterTitle": "Reflection, Attributes, and Dynamic Programming",
+ "SanitizedSubsection": "Assemblies",
+ "ActualSubsection": "Caller* Attributes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO choose meaningful names for type parameters and prefix the name with T.",
+ "ChapterNumber": 12,
+ "ChapterTitle": "Generics",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Type Parameter Naming Guidelines"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER indicating a constraint in the name of a type parameter.",
+ "ChapterNumber": 12,
+ "ChapterTitle": "Generics",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Type Parameter Naming Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO place multiple generic semantically equivalent classes into a single file if they differ only by the number of generic parameters.",
+ "ChapterNumber": 12,
+ "ChapterTitle": "Generics",
+ "SanitizedSubsection": "Parameters",
+ "ActualSubsection": "Multiple Type Parameters"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID shadowing a type parameter of an outer type with an identically named type parameter of a nested type.",
+ "ChapterNumber": 12,
+ "ChapterTitle": "Generics",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Nested Generic Types"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID unsafe array covariance. Instead, CONSIDER converting the array to the read-only interface IEnumerable\u003CT\u003E, which can be safely converted via covariant conversions.",
+ "ChapterNumber": 12,
+ "ChapterTitle": "Generics",
+ "SanitizedSubsection": "Arrays",
+ "ActualSubsection": "Support for Unsafe Covariance in Arrays"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use parallel loops when the computations performed can be easily split up into many mutually independent processor-bound computations that can be executed in any order on any thread.",
+ "ChapterNumber": 21,
+ "ChapterTitle": "Iterating in Parallel",
+ "SanitizedSubsection": "Branches",
+ "ActualSubsection": "Executing Loop Iterations in Parallel"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID placing more than one class in a single source file.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Classes",
+ "ActualSubsection": "Declaring and Instantiating a Class"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO name the source file with the name of the public type it contains.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Classes",
+ "ActualSubsection": "Declaring and Instantiating a Class"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID target-typed new expressions when the data type of the constructor is not obvious.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER use target-typed new expressions when the data type of the constructor is obvious.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use properties for simple access to simple data with simple computations.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID throwing exceptions from property getters.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO preserve the original property value if the property throws an exception.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using the same casing on a property\u2019s backing field as that used in the property, distinguishing the backing field with an \u201C_\u201D prefix.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO name properties using a noun, noun phrase, or adjective.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER giving a property the same name as its type.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID naming fields with camelCase.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor prefixing Boolean properties with \u201CIs,\u201D \u201CCan,\u201D or \u201CHas,\u201D when that practice adds value.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO declare all instance fields as private (and expose them via a property).",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO name properties with PascalCase.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor automatically implemented properties over fields.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor automatically implemented properties over using fully expanded ones if there is no additional implementation logic.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Property and Field Guidelines"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID accessing the backing field of a property outside the property, even from within the containing class.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Using Properties with Validation"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO create read-only properties if the property value should not be changed.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Read-Only and Write-Only Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO create read-only automatically implemented properties, rather than read-only properties with a backing field if the property value should not be changed.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Read-Only and Write-Only Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO apply appropriate accessibility modifiers on implementations of getters and setters on all properties.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Access Modifiers on Getters and Setters"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT provide set-only properties or properties with the setter having broader accessibility than the getter.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Access Modifiers on Getters and Setters"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide sensible defaults for all properties, ensuring that defaults do not result in a security hole or significantly inefficient code.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Object Initializers"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO allow properties to be set in any order, even if this results in a temporarily invalid object state.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Object Initializers"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the same name for constructor parameters (camelCase) and properties (PascalCase) if the constructor parameters are used to simply set the property.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Overloading Constructors"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide constructor optional parameters or constructor overloads that initialize properties with good defaults.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Overloading Constructors"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement non-nullable read/write reference fully implemented properties with a nullable backing field, a null-forgiveness operator when returning the field from the getter, and non-null validation in the property setter.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Read-Only Automatically Implemented Reference Type Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO assign non-nullable reference type properties before instantiation completes.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Read-Only Automatically Implemented Reference Type Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement non-nullable reference type automatically implemented properties as read-only.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Read-Only Automatically Implemented Reference Type Properties"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use a nullable check for all reference type properties and fields that are not initialized before instantiation completes.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Properties",
+ "ActualSubsection": "Read-Only Automatically Implemented Reference Type Properties"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use constructor parameters to initialize required properties; instead, rely on object initializer\u2013specified values.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "required Modifier"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use the SetRequiredParameters attribute unless all required parameters are assigned valid values during construction.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "required Modifier"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER having a default constructor only on types with required parameters, relying on the object initializer to set both required and non-required members.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "required Modifier"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID adding required members to released types to avoid breaking the compile on existing code.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "required Modifier"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID required members where the default value of the type is valid.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "required Modifier"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER initializing static fields inline rather than explicitly using static constructors or declaration assigned values.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Static Constructors"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID frivolously defining extension methods, especially on types you don\u2019t own.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Extension Methods"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use constant fields for values that will never change.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Fields",
+ "ActualSubsection": "const"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID constant fields for values that will change over time.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Fields",
+ "ActualSubsection": "const"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor read-only automatically implemented properties over read-only fields.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "readonly"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID publicly exposed nested types. The only exception is if the declaration of such a type is unlikely or pertains to an advanced customization scenario.",
+ "ChapterNumber": 6,
+ "ChapterTitle": "Classes",
+ "SanitizedSubsection": "Classes",
+ "ActualSubsection": "Nested Classes"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use query expression syntax to make queries easier to read, particularly if they involve complex from, let, join, or group clauses.",
+ "ChapterNumber": 16,
+ "ChapterTitle": "LINQ with Query Expressions",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Query Expressions Are Just Method Invocations"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using the standard query operators (method call form) if the query involves operations that do not have a query expression syntax, such as Count(), TakeWhile(), or Distinct().",
+ "ChapterNumber": 16,
+ "ChapterTitle": "LINQ with Query Expressions",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Query Expressions Are Just Method Invocations"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the C# keyword rather than the unqualified name when specifying a data type (e.g., string rather than String).",
+ "ChapterNumber": 2,
+ "ChapterTitle": "Data Types",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Type Name Forms"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor consistency rather than variety within your code.",
+ "ChapterNumber": 2,
+ "ChapterTitle": "Data Types",
+ "SanitizedSubsection": "Types",
+ "ActualSubsection": "Type Name Forms"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use uppercase literal suffixes (e.g., 1.618033988749895M).",
+ "ChapterNumber": 2,
+ "ChapterTitle": "Data Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Literal Values"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO rely on System.Console.WriteLine() and System.Environment.NewLine rather than \\n to accommodate Windows-specific operating system idiosyncrasies with the same code that runs on Linux and macOS.",
+ "ChapterNumber": 2,
+ "ChapterTitle": "Data Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Newline"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT throw exceptions from within the implementation of operator overloading.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Comparison Operators (==, !=, \u003C, \u003E, \u003C=, \u003E=)"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT provide an implicit conversion operator if the conversion is lossy.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Conversions",
+ "ActualSubsection": "Guidelines for Conversion Operators"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT throw exceptions from implicit conversions.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Conversions",
+ "ActualSubsection": "Guidelines for Conversion Operators"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use file-scoped namespaces (C# 10.0 or later).",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Defining Namespaces"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO prefix namespace names with a company name to prevent namespaces from different companies having the same name.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Defining Namespaces"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use a stable, version-independent product name at the second level of a namespace name.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Defining Namespaces"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT define types without placing them into a namespace.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Defining Namespaces"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER creating a folder structure that matches the namespace hierarchy.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Defining Namespaces"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide XML comments on public APIs when they provide more context than the API signature alone. This includes member descriptions, parameter descriptions, and examples of calling the API.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Files",
+ "ActualSubsection": "Generating an XML Documentation File"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement the dispose pattern on objects with resources that are scarce or expensive.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement IDisposable to support possible deterministic finalization on classes with finalizers.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement finalizer methods only on objects with resources that don\u0027t have finalizers but still require cleanup.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO refactor a finalization method to call the same code as IDisposable, perhaps simply by calling the Dispose() method.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT throw exceptions from finalizer methods.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER registering the finalization code with the AppDomain.ProcessExit to increase the probability that resource cleanup will execute before the process exits.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO unregister any AppDomain.ProcessExit events during dispose.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO call System.GC.SuppressFinalize() from Dispose() to avoid repeating resource cleanup and delaying garbage collection on an object.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO ensure that Dispose() is idempotent (it should be possible to call Dispose() multiple times).",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO keep Dispose() simple, focusing on the resource cleanup required by finalization.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID calling Dispose() on owned objects that have a finalizer. Instead, rely on the finalization queue to clean up the instance.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID referencing other objects that are not being finalized during finalization.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO invoke a base class\u2019s Dispose() method when overriding Dispose().",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER ensuring that an object becomes unusable after Dispose() is called. After an object has been disposed, methods other than Dispose() (which could potentially be called multiple times) should throw an ObjectDisposedException.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO implement IDisposable on types that own disposable fields (or properties) and dispose of those instances.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO invoke a base class\u2019s Dispose() method from the Dispose(bool disposing) method if one exists.",
+ "ChapterNumber": 10,
+ "ChapterTitle": "Well-Formed Types",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Garbage Collection, Finalization, and IDisposable"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor composite formatting over use of the addition operator for concatenating strings when localization is a possibility.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Strings",
+ "ActualSubsection": "Using the Addition Operator with Strings"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID binary floating-point types when exact decimal arithmetic is required; use the decimal floating-point type instead.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Special Floating-Point Characteristics"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID using equality conditionals with binary floating-point types. Either subtract the two values and see if their difference is less than a tolerance or use the decimal type.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID confusing usage of the increment and decrement operators.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Increment/decrement",
+ "ActualSubsection": "Increment and Decrement Operators (\u002B\u002B, --)"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO be cautious when porting code between C, C\u002B\u002B, and C# that uses increment and decrement operators; C and C\u002B\u002B implementations need not follow the same rules as C#.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Increment/decrement",
+ "ActualSubsection": "Increment and Decrement Operators (\u002B\u002B, --)"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use a constant for any value that can possibly change over time. The value of pi and the number of protons in an atom of gold are constants; the price of gold, the name of your company, and the version number of your program can change.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Constant Expressions and Constant Locals"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID omitting braces, except for the simplest of single-line if statements.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Code Blocks ({})"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER using an if-else statement instead of an overly complicated conditional expression.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Branches",
+ "ActualSubsection": "Conditional Operator (?:)"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER refactoring the method to make the control flow easier to understand if you find yourself writing for loops with complex conditionals and multiple loop variables.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Branches",
+ "ActualSubsection": "The for Loop"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the for loop when the number of loop iterations is known in advance and the \u201Ccounter\u201D that gives the number of iterations executed is needed in the loop.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use the while loop when the number of loop iterations is not known in advance and a counter is not needed.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use continue as the jump statement that exits a switch section. This is legal when the switch is inside a loop, but it is easy to become confused about the meaning of break in a later switch section.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Branches",
+ "ActualSubsection": "The Basic switch Statement"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID using goto.",
+ "ChapterNumber": 4,
+ "ChapterTitle": "Operators and Control Flow",
+ "SanitizedSubsection": "Branches",
+ "ActualSubsection": "The goto Statement"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO give methods names that are verbs or verb phrases.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Methods",
+ "ActualSubsection": "Calling a Method"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use PascalCasing for namespace names.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Namespaces"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER organizing the directory hierarchy for source code files to match the namespace hierarchy.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Namespaces",
+ "ActualSubsection": "Namespaces"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use camelCasing for parameter names.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Parameters",
+ "ActualSubsection": "Formal Parameter Declaration"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use parameter arrays when a method can handle any number\u2014including zero\u2014of additional arguments.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Arrays",
+ "ActualSubsection": "Parameter Arrays (params)"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide good defaults for all parameters where possible.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Parameters",
+ "ActualSubsection": "Optional Parameters"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO provide simple method overloads that have a small number of required parameters.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Parameters",
+ "ActualSubsection": "Optional Parameters"
+ },
+ {
+ "Type": 3,
+ "Guideline": "CONSIDER organizing overloads from the simplest to the most complex.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Parameters",
+ "ActualSubsection": "Optional Parameters"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO treat parameter names as part of the API, and avoid changing the names if version compatibility between APIs is important.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID explicitly throwing exceptions from finally blocks. (Implicitly thrown exceptions resulting from method calls are acceptable.)",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Trapping Errors"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO favor try/finally and avoid using try/catch for cleanup code.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Trapping Errors"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO throw exceptions that describe which exceptional circumstance occurred and, if possible, how to prevent it.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Trapping Errors"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID general catch blocks and replace them with a catch of System.Exception.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID catching exceptions for which the appropriate action is unknown. It is better to let an exception go unhandled than to handle it incorrectly.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": null
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO prefer using an empty throw when catching and rethrowing an exception, to preserve the call stack.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Reporting Errors Using a throw Statement"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO report execution failures by throwing exceptions rather than returning error codes.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Reporting Errors Using a throw Statement"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT have public members that return exceptions as return values or an out parameter. Throw exceptions to indicate errors; do not use them as return values to indicate errors.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Reporting Errors Using a throw Statement"
+ },
+ {
+ "Type": 2,
+ "Guideline": "AVOID catching and logging an exception before rethrowing it. Instead, allow the exception to escape until it can be handled appropriately.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Reporting Errors Using a throw Statement"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO verify that non-null reference types parameters are not null and throw an ArgumentNullException when they are.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Reporting Null Argument Exceptions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use ArgumentException.ThrowIfNull() to verify values are null in .NET 7.0 or later.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Reporting Null Argument Exceptions"
+ },
+ {
+ "Type": 4,
+ "Guideline": "DO use nameof(value) (which resolves to \u0022value\u0022) for the paramName argument when creating ArgumentException() or ArgumentNullException() type exceptions. (value is the implicit name of the parameter on property setters.)",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Miscellaneous",
+ "ActualSubsection": "Introducing the nameof Operator"
+ },
+ {
+ "Type": 1,
+ "Guideline": "DO NOT use exceptions for handling normal, expected conditions; use them for exceptional, unexpected conditions.",
+ "ChapterNumber": 5,
+ "ChapterTitle": "Parameters and Methods",
+ "SanitizedSubsection": "Exceptions",
+ "ActualSubsection": "Avoid Using Exception Handling to Deal with Expected Situations"
+ }
+]
\ No newline at end of file
diff --git a/EssentialCSharp.Web/Placeholders/sitemap.json b/EssentialCSharp.Web/Placeholders/sitemap.json
index e7dc316e..c43e0b62 100644
--- a/EssentialCSharp.Web/Placeholders/sitemap.json
+++ b/EssentialCSharp.Web/Placeholders/sitemap.json
@@ -1,6 +1,108 @@
[
{
- "Key": "hello-world",
+ "Keys": [
+ "introducing-c"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Overview",
+ "ContentHash": "74B5",
+ "AnchorId": "overview",
+ "IndentLevel": 0,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "hello-world"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Hello, World",
+ "ContentHash": "C68C",
+ "AnchorId": "hello-world",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "creating-editing-compiling-and-running-c-source-code"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 2,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Creating, Editing, Compiling, and Running C# Source Code",
+ "ContentHash": "8185",
+ "AnchorId": "creating-editing-compiling-and-running-c-source-code",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "with-dotnet-cli"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 3,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "With Dotnet CLI",
+ "ContentHash": "E879",
+ "AnchorId": "with-dotnet-cli",
+ "IndentLevel": 3,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "with-visual-studio-2022-windows-or-mac"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 4,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "With Visual Studio 2022 (Windows or Mac)",
+ "ContentHash": "ECF8",
+ "AnchorId": "with-visual-studio-2022-windows-or-mac",
+ "IndentLevel": 3,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "understanding-a-project"
+ ],
"PagePath": [
"Chapters",
"01",
@@ -9,9 +111,672 @@
],
"ChapterNumber": 1,
"PageNumber": 1,
- "ChapterTitle": "Hello World",
- "RawHeading": "Local Development Placeholder",
- "AnchorId": "helloworld",
- "IndentLevel": 0
+ "OrderOnPage": 5,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Understanding a Project",
+ "ContentHash": "E9E5",
+ "AnchorId": "understanding-a-project",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "compilation-and-execution"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 6,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Compilation and Execution",
+ "ContentHash": "A4C6",
+ "AnchorId": "compilation-and-execution",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "essential-c-source-code"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 1,
+ "OrderOnPage": 7,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Essential C# Source Code",
+ "ContentHash": "527F",
+ "AnchorId": "essential-c-source-code",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "c-syntax-fundamentals"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "C# Syntax Fundamentals",
+ "ContentHash": "983A",
+ "AnchorId": "c-syntax-fundamentals",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "statements-and-statement-delimiters"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Statements and Statement Delimiters",
+ "ContentHash": "A624",
+ "AnchorId": "statements-and-statement-delimiters",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "introducing-a-class-and-a-method"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 2,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Introducing a Class and a Method",
+ "ContentHash": "F9FF",
+ "AnchorId": "introducing-a-class-and-a-method",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "c-keywords"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 3,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "C# Keywords",
+ "ContentHash": "1E24",
+ "AnchorId": "c-keywords",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "identifiers"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 4,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Identifiers",
+ "ContentHash": "8156",
+ "AnchorId": "identifiers",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "type-definition"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 5,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Type Definition",
+ "ContentHash": "FA33",
+ "AnchorId": "type-definition",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "main-method"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 6,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Main Method",
+ "ContentHash": "52B1",
+ "AnchorId": "main-method",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "whitespace"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 2,
+ "OrderOnPage": 7,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Whitespace",
+ "ContentHash": "0151",
+ "AnchorId": "whitespace",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "working-with-variables"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "03.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 3,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Working with Variables",
+ "ContentHash": "134A",
+ "AnchorId": "working-with-variables",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "introducing-data-types"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "03.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 3,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Introducing Data Types",
+ "ContentHash": "EC83",
+ "AnchorId": "introducing-data-types",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "declaring-a-variable"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "03.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 3,
+ "OrderOnPage": 2,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Declaring a Variable",
+ "ContentHash": "98A8",
+ "AnchorId": "declaring-a-variable",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "assigning-a-variable"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "03.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 3,
+ "OrderOnPage": 3,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Assigning a Variable",
+ "ContentHash": "0143",
+ "AnchorId": "assigning-a-variable",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "using-a-variable"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "03.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 3,
+ "OrderOnPage": 4,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Using a Variable",
+ "ContentHash": "8C38",
+ "AnchorId": "using-a-variable",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "console-input-and-output"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "04.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 4,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Console Input and Output",
+ "ContentHash": "C93C",
+ "AnchorId": "console-input-and-output",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "getting-input-from-the-console"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "04.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 4,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Getting Input from the Console",
+ "ContentHash": "A17C",
+ "AnchorId": "getting-input-from-the-console",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "writing-output-to-the-console"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "04.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 4,
+ "OrderOnPage": 2,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Writing Output to the Console",
+ "ContentHash": "A935",
+ "AnchorId": "writing-output-to-the-console",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "comments"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "04.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 4,
+ "OrderOnPage": 3,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Comments",
+ "ContentHash": "F51C",
+ "AnchorId": "comments",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "debugging"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "04.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 4,
+ "OrderOnPage": 4,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Debugging",
+ "ContentHash": "B9AA",
+ "AnchorId": "debugging",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "managed-execution-and-the-common-language-infrastructure"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "05.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 5,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Managed Execution and the Common Language Infrastructure",
+ "ContentHash": "0B6A",
+ "AnchorId": "managed-execution-and-the-common-language-infrastructure",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "common-intermediate-language-and-ildasm"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "05.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 5,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Common Intermediate Language and Ildasm",
+ "ContentHash": "2200",
+ "AnchorId": "common-intermediate-language-and-ildasm",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "multiple-net-frameworks"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "06.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 6,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Multiple .NET Frameworks",
+ "ContentHash": "9CE9",
+ "AnchorId": "multiple-net-frameworks",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "application-programming-interface"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "06.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 6,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Application Programming Interface",
+ "ContentHash": "941F",
+ "AnchorId": "application-programming-interface",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "c-and-net-versioning"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "06.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 6,
+ "OrderOnPage": 2,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "C# and .NET Versioning",
+ "ContentHash": "3503",
+ "AnchorId": "c-and-net-versioning",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "chapter-1-summary"
+ ],
+ "PagePath": [
+ "Chapters",
+ "01",
+ "Pages",
+ "07.html"
+ ],
+ "ChapterNumber": 1,
+ "PageNumber": 7,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Introducing C#",
+ "RawHeading": "Chapter 1: Summary",
+ "ContentHash": "DE96",
+ "AnchorId": "chapter-1-summary",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "data-types"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 1,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Overview",
+ "ContentHash": "61DD",
+ "AnchorId": "overview",
+ "IndentLevel": 0,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "type-name-forms"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "01.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 1,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Type Name Forms",
+ "ContentHash": "BAB3",
+ "AnchorId": "type-name-forms",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "fundamental-numeric-types"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 2,
+ "OrderOnPage": 0,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Fundamental Numeric Types",
+ "ContentHash": "7EC2",
+ "AnchorId": "fundamental-numeric-types",
+ "IndentLevel": 1,
+ "IncludeInSitemapXml": true
+ },
+ {
+ "Keys": [
+ "integer-types"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 2,
+ "OrderOnPage": 1,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Integer Types",
+ "ContentHash": "FB7E",
+ "AnchorId": "integer-types",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "floating-point-types-float-double"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 2,
+ "OrderOnPage": 2,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Floating-Point Types (float, double)",
+ "ContentHash": "95AB",
+ "AnchorId": "floating-point-types-float-double",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "decimal-type"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 2,
+ "OrderOnPage": 3,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Decimal Type",
+ "ContentHash": "7C20",
+ "AnchorId": "decimal-type",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
+ },
+ {
+ "Keys": [
+ "literal-values"
+ ],
+ "PagePath": [
+ "Chapters",
+ "02",
+ "Pages",
+ "02.html"
+ ],
+ "ChapterNumber": 2,
+ "PageNumber": 2,
+ "OrderOnPage": 4,
+ "ChapterTitle": "Data Types",
+ "RawHeading": "Literal Values",
+ "ContentHash": "BFB8",
+ "AnchorId": "literal-values",
+ "IndentLevel": 2,
+ "IncludeInSitemapXml": false
}
]
\ No newline at end of file