CHAPTER 1 - Introducing the .NET Platform
In This Chapter
- What Is .NET?
- The Common Language Runtime (CLR)
- The .NET Framework Class Library (FCL)
- C# and Other .NET Languages
- The Common Type System (CTS)
- The Common Language Specification (CLS)
As a C# developer, it’s important to understand the environment you are building applications on: Microsoft .NET (pronounced “Dot Net”). After all, your design and development decisions will often be influenced by code-compilation practicalities, the results of compilation, and the behavior of applications in the runtime environment. The foundation of all .NET development begins here, and throughout this book I occasionally refer back to this chapter when explaining concepts that affect the practical implementation of C#.
By learning about the .NET environment, you can gain an understanding of what .NET is and what it means to you. You learn about the parts of .NET, including the Common Language Runtime (CLR), the .NET Framework Class Library, and how .NET supports multiple languages. Along the way, you see how the parts of .NET tie together, their relationships, and what they do for you. First, however, you need to know what .NET is, which is explained in the next section.
What Is .NET?
Microsoft .NET, which I refer to as just .NET, is a platform for developing “managed” software. The word managed is key here-a concept setting the .NET platform apart from many other development environments. I’ll explain what the word managed means and why it is an integral capability of the .NET platform.
When referring to other development environments, as in the preceding paragraph, I’m focusing on the traditional practice of compiling to an executable file that contains machine code and how that file is loaded and executed by the operating system. Figure 1.1 shows what I mean about the traditional compilation-to-execution process.
Figure 1.1 Traditional compilation.
In the traditional compilation process, the executable file is binary and can be executed by the operating system immediately. However, in the managed environment of .NET, the file produced by the compiler (the C# compiler in our case) is not an executable binary. Instead, it is an assembly, shown in Figure 1.2, which contains metadata and intermediate language code.
Figure 1.2 Managed compilation.
As mentioned in the preceding paragraph, an assembly contains intermediate language and metadata rather than binary code. This intermediate language is called Microsoft Intermediate Language (MSIL), which is commonly referred to as IL. IL is a high-level, component-based assembly language. In later sections of this chapter, you learn how IL supports a common type system and multiple languages in the same platform.
.NET has been standardized by both the European Computer Manufacturers Association (ECMA) and the Open Standards Institute (OSI). The standard is referred to as the Common Language Infrastructure (CLI). Similarly, the standardized term for IL is Common Intermediate Language (CIL).
In addition to .NET, there are other implementations of CIL-the two most well known by Microsoft and Novell. Microsoft’s implementation is an open source offering for the purposes of research and education called the Shared Source Common Language Infrastructure (SSCLI). The Novell offering is called Mono, which is also open source.
Beyond occasional mention, this book focuses mainly on the Microsoft .NET implementation of the CLI standard.
The other part of an assembly is metadata, which is extra information about the code being used in the assembly. Figure 1.3 shows the contents of an assembly.
Figure 1.3 Assembly contents.
Figure 1.3 is a simplified version of an assembly, showing only those parts pertaining to the current discussion. Assemblies have other features that illustrate the difference between an assembly and an executable file. Specifically, the role of an assembly is to be a unit of deployment, execution, identity, and security in the managed environment. In Part X, Chapters 43 and 44 explain more about the role of the assembly in deployment, identity, and security. The fact that an assembly contains metadata and IL, instead of only binary code, has a significant advantage, allowing execution in a managed environment. The next section explains how the CLR uses the features of an assembly to manage code during execution.
The Common Language Runtime (CLR)
As introduced in the preceding section, C# applications are compiled to IL, which is executed by the CLR. This section highlights several features of the CLR. You’ll also see how the CLR manages your application during execution.
Why Is the CLR Important?
In many traditional execution environments of the past, programmers needed to perform a lot of the low-level work (plumbing) that applications needed to support. For example, you had to build custom security systems, implement error handling, and manage memory.
The degree to which these services were supported on different language platforms varied considerably. Visual Basic (VB) programmers had built-in memory management and an error-handling system, but they didn’t always have easy access to all the features of COM+, which opened up more sophisticated security and transaction processing. C++ programmers have full access to COM+ and exception handling, but memory management is a totally manual process. In a later section, you learn about how .NET supports multiple languages, but knowing just a little about a couple of popular languages and a couple of the many challenges they must overcome can help you to understand why the CLR is such a benefit for a C# developer.
The CLR solves many problems of the past by offering a feature-rich set of plumbing services that all languages can use. The features described in the next section further highlight the value of the CLR.
This section describes, more specifically, what the CLR does for you. Table 1.1 summarizes CLR features with descriptions and chapter references (if applicable) in this book where you can find more detailed information.
In addition to the descriptions provided in Table 1.1, the following sections expand upon a few of the CLR features. These features are included in the CLR execution process.
The CLR Execution Process
Beyond just executing code, parts of the execution process directly affect your application design and how a program behaves at runtime. Many of these subjects are handled throughout this book, but this section highlights specific additional items you should know about.
From the time you or another process selects a .NET application for execution, the CLR executes a special process to run your application, shown in Figure 1.4.
Figure 1.4 The CLR execution process (summarized).
As illustrated in Figure 1.4, Windows (the OS) will be running at Start; the CLR won’t begin execution until Windows starts it. When an application executes, OS inspects the file to see whether it has a special header to indicate that it is a .NET application. If not, Windows continues to run the application.
If an application is for .NET, Windows starts up the CLR and passes the application to the CLR for execution. The CLR loads the executable assembly, finds the entry point, and begins its execution process.
The executable assembly could reference other assemblies, such as dynamic link libraries (DLLs), so the CLR will load those. However, this is on an as-needed basis. An assembly won’t be loaded until the CLR needs access to the assembly’s code. It’s possible that the code in some assemblies won’t be executed, so there isn’t a need to use resources unless absolutely necessary.
As mentioned previously, the C# compiler produces IL as part of an assembly’s output. To execute the code, the CLR must translate the IL to binary code that the operating system understands. This is the responsibility of the JIT compiler.
As its name implies, the JIT compiler only compiles code before the first time that it executes. After the IL is compiled to machine code by the JIT compiler, the CLR holds the compiled code in a working set. The next time that the code must execute, the CLR checks its working set and runs the code directly if it is already compiled. It is possible that the working set could be paged out of memory during program execution, for various reasons that are necessary for efficient operation of the CLR on the particular machine it is running on. If more memory is available than the size of the working set, the CLR can hold on to the code. Additionally, in the case of Web applications where scalability is an issue, the working set can be swapped out due to periodic recycling or heavier load on the server, resulting in additional load time for subsequent requests.
The JIT compiler operates at the method level. If you aren’t familiar with the term method, it is essentially the same as a function or procedure in other languages. Therefore, when the CLR begins execution, the JIT compiler compiles the entry point (the Main method in C#). Each subsequent method is JIT compiled just before execution. If a method being JIT compiled contains calls to methods in another assembly, the CLR loads that assembly (if not already loaded).
This process of checking the working set, JIT compilation, assembly loading, and execution continues until the program ends.
The meaning to you in the CLR execution process is in the form of application design and understanding performance characteristics. In the case of assembly loading, you have some control over when certain code is loaded. For example, if you have code that is seldom used or necessary only in specialized cases, you could separate it into its own DLL, which will keep the CLR from loading it when not in use. Similarly, separating seldomly executed logic into a separate method ensures the code doesn’t JIT until it’s called.
Another detail you might be concerned with is application performance. As described earlier, code is loaded and JIT compiled. Another DLL adds load time, which may or may not make a difference to you, but it is certainly something to be aware of. By the way, after code has been JIT compiled, it executes as fast as any other binary code in memory.
One of the CLR features listed in Table 1.1 is .NET Framework Class Library (FCL) support. The next section goes beyond FCL support for the CLR and gives an overview of what else the FCL includes.
The .NET Framework Class Library (FCL)
.NET has an extensive library, offering literally thousands of reusable types. Organized into namespaces, the FCL contains code supporting all the .NET technologies, such as Windows Forms, Windows Presentation Foundation, ASP.NET, ADO.NET, Windows Workflow, and Windows Communication Foundation. In addition, the FCL has numerous cross-language technologies, including file I/O, networking, text management, and diagnostics. As mentioned earlier, the FCL has CLR support in the areas of built-in types, exception handling, security, and threading. Table 1.2 shows some common FCL libraries.
What Is a Type?
Types are used to define the meaning of variables in your code. They could be built-in types such as int, double, or string. You can also have custom types such as Customer, Employee, or BankAccount. Each type has optional data/behavior associated with it.
Much of this book is dedicated to explaining the use of types, whether built-in, custom, or those belonging to the .NET FCL. Chapter 4, “Understanding Reference Types and Value Types,” includes a more in-depth discussion on how C# supports the .NET type system.
The namespaces in Table 1.2 are a sampling from the many available in the .NET Framework. They’re representative of the types they contain. For example, you can find Windows Presentation Foundation (WPF) libraries in the System.Windows namespace, Windows Communication Foundation (WCF) is in the System.ServiceModel namespace, and Language Integrated Query (LINQ) types can be found in the System.Linq namespace.
Another aspect of Table 1.2 is that I included only two levels in the namespace hierarchy, System.*. In fact, there are multiple namespace levels, depending on which technology you view. For example, if you want to write code using the Windows Workflow (WF) runtime, you look in the System.Workflow.Runtime namespace. Generally, you can find the more common types at the higher namespace levels.
One of the benefits you should remember about the FCL is the amount of code reuse it offers. As you read through this book, you’ll see many examples of how the FCL forms the basis for code you can write. For example, you learn how to create your own exception object in Chapter 13, “Naming and Organizing Types with Namespaces,” which requires that you use the Exception types from the FCL. Even if you encounter situations that don’t require your use of FCL code, you can still use it. An example of when you would want to reuse FCL code is in Chapter 17, “Parameterizing Type with Generics and Writing Iterators,” where you learn how to use existing generic collection classes. The FCL was built and intended for reuse, and you can often be much more productive by using FCL types rather than building your own from scratch.
Another important feature of the FCL is language neutrality. Just like the CLR, it doesn’t matter which .NET language you program in-the FCL is reusable by all .NET programming languages, which are discussed in the next section.
C# and Other .NET Languages
.NET supports multiple programming languages, which are assisted by both the CLR and the FCL. Literally dozens of languages target the .NET CLR as a platform. Table 1.3 lists some of these languages.
Table 1.3 is not a comprehensive list because there are new languages being created for .NET on a regular basis. An assumption one could make from this growing list is that .NET is a successful multilanguage platform.
As you learned earlier in this chapter, the C# compiler emits IL. However, the C# compiler is not alone-all compilers for languages in Table 1.2 emit IL, too. By having a CLR that consumes IL, anyone can build a compiler that emits IL and join the .NET family of languages.
In the next section, you learn how the CLR supports multiple languages via a Common Type System (CTS), the relationship of the languages via a Common Language Specification (CLS), and how languages are supported via the FCL.
The Common Type System (CTS)
To support multiple programming languages on a single CLR and have the ability to reuse the FCL, the types of each programming language must be compatible. This binary compatibility between language types is called the Common Type System (CTS).
The built-in types are represented as types in the FCL. This means that a C# int is the same as a VB.NET Integer type and their .NET type is System.Int32, which is a 32-bit integer named Int32 in the System namespace of the FCL. You’ll learn more about C# types, type classification, and how C# types map to the CTS in Chapter 4.
The Common Language Specification (CLS)
Although the CLR understands all types in the CTS, each language targeting the CLR will not implement all types. Languages must often be true to their origins and will not lose their features or add new features that aren’t compatible with how they are used.
However, one of the benefits of having a CLR with a CTS that understands IL, and an FCL that supports all languages, is the ability to write code in one language that is consumable by other languages. Imagine you are a third-party component vendor and your language of choice is C#. It would be desirable that programmers in any .NET language (for example, IronRuby or Delphi) would be able to purchase and use your components.
For programming languages to communicate effectively, targeting IL is not enough. There must be a common set of standards to which every .NET language must adhere. This common set of language features is called the Common Language Specification (CLS).
Most .NET compilers can produce both CLS-compliant and non-CLS-compliant code, and it is up to the developer to choose which language features to use. For example, C# supports unsigned types, which are non-CLS compliant. For CLS compliance, you can still use unsigned types within your code so long as you don’t expose them in the public interface of your code, where code written in other languages can see.
.NET is composed of a CLR and the .NET FCL, and supports multiple languages. The CLR offers several features that free you from the low-level plumbing work required in other environments. The FCL is a large library of code that supports additional technologies such as Windows Presentation Foundation, Windows Communication Foundation, Windows Workflow, ASP.NET, and many more. The FCL also contains much code that you can reuse in your own applications. Through its support of IL, a CTS, and a CLS, many languages target the .NET platform. Therefore, you can write a reusable library with C# code that can be consumed by code written in other programming languages.
Remember that understanding the .NET platform, which includes CLR, FCL, and multiple-language support, has implications in the way you design and write your code. Throughout this book, you’ll encounter many instances where the concepts in this chapter lay the foundation of the tasks you need to accomplish. You might want to refer back to this chapter for an occasional refresher.
This chapter has been purposefully as short as possible to cover only the platform issues most essential to building C# applications. If you’re like me, you’ll be eager to jump into some code. The next chapter does that by introducing you to essential syntax of the C# programming language.