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