Introducing C# and .NET 6
Exploring Some Key Benefits of the .NET Platform
Support for numerous programming languages, a common runtime engine shared by all .NET languages, language integration with cross-language inheritance, cross-language exception handling, and cross-language debugging, a comprehensive base class library, a simplified deployment model, and extensive command-line support.
Understanding the .NET Support Lifecycle
Previewing the Building Blocks of the .NET Platform
From a programmer's point of view, .NET can be understood as a runtime environment and a comprehensive base class library. The Common Type System describes all possible data types and programming constructs supported by the runtime and how they are represented in the .NET metadata format. A given .NET language may not support every programming construct supported by the CTS. The Common Language Specification is a related specification that defines a subset of common types and programming constructs that all .NET programming languages agree on.
The Role of the Base Class Libraries
The base class libraries can be referred to as BCLs. The BCLs are available to all .NET programming languages. The included types encapsulate various primitives like threads, file input/output, graphical rendering systems, and interaction with external hardware. It also provides support for a number of services required by most real-world applications.
The Role of .NET Standard
.NET Standard is a specification that defines the availability of .NET APIs and BCLs that must be available in each implementation.
What C# Brings to the Table
C# is a programming language with syntax that is very similar looking to Java. In reality, both C# and Java are members of the C family of programming languages. Many of C#'s syntactical constructs are modeled after aspects of Visual Basic and C++. C# also supports a number of features like lambda expressions and anonymous types traditionally found in functional languages like Lisp. Language Integrated Query (LINQ) allows C# to support a number of constructs that make it unique. C# is a language with the syntactical cleanness of Java and power and flexibility of C++.
Managed vs Unmanaged code
The C# language can only be used to build software that is hosted under the .NET runtime. Managed code refers to code targeting the .NET runtime. The binary unit that contains the managed code is termed an assembly. Unmanaged code is code that cannot be directly hosted by the .NET runtime.
Using Additional .NET-Aware Programming Languages
The other two languages supported directly by Microsoft that can build .NET applications are Visual Basic and F#.
Getting an Overview of .NET Assemblies
Regardless of the language used, the .NET binaries take the same form as unmanaged Windows binaries (*.dll) but have absolutely no internal similarities. .NET binaries do not contain platform-specific instructions but rather platform-agnostic Intermediate Language and type metadata. IL is also known as Microsoft Intermediate Language and Common Intermediate Language. In this book it is referred to as CIL.
When a *.dll has been created using a .NET compiler, the binary blob is termed an assembly. Unlike .NET Framework assemblies that can be either a *.dll or *.exe, .NET projects are always compiled to a file with a .dll extension. Executable .NET assemblies are executed with the dotnet command. An assembly contains CIL code which is conceptually similar to Java bytecode in that it is not compiled to platform-specific instructions until necessary. Assembles contain metadata that describes in detail the characteristics of every "type" within the binary. The assemblies also contain metadata about themselves using a manifest.
The C# compiler emits CIL, not platform-specific instructions. This is true of all .NET compilers. Because CIL is platform-agnostic, .NET can be platform-agnostic. Compiling code into CIL also allows for the language integration between the different .NET languages.
CIL code is compiled on the fly by a JIT compiler called jitter. A given jitter is optimized for its underlying platform and caches results in memory in a manner suited to the target operating system.
The .NET type metadata in the assembly makes the assembly a completely-self describing entity. This metadata is used by numerous aspects of the .NET runtime environment as well as various development tools such as the IntelliSense feature of Visual Studio. The metadata is also the backbone of numerous .NET technologies such as reflection, late binding, and object serialization.
The .NET assembly metadata that describes the assembly itself, the manifest, documents various characteristics of the assembly itself as well as external assemblies that are required.
The Common Type System
In the .NET world, a type is a general term used to refer to a member from the set {class, interface, structure, enumeration, delegate}. The CTS is a formal specification that documents how types must be defined in order to be hosted by the .NET Runtime.
Every .NET language supports the notion of a class type.
Interfaces are nothing more than a named collection of abstract member definitions and/or default implementations that are implemented by a given class or structure. In C#, they are defined using the interface keyword. By convention, all .NET interfaces begin with a capital letter I.
Structure types are user-defined types that will be familiar to those with a C background, although they behave a bit differently under the hood. A structure can be thought of as a lightweight class type with value-based semantics. They may be best suited for modeling geometric and mathematical data, and are created in C# using the struct keyword.
Enumerations are a handy programming construct to group name-value pairs.
Delegates are the .NET equivalent of a type-safe, C-style function pointer. The key difference is that a .NET delegate is a class that derives from System.MulticastDelegate. In C#, they are declared using the delegate keyword. Delegates are critical when you want to provide a way for one object to forward a call to another object. They provide the foundation for the .NET event architecture. They have intrinsic support for multicasting and asynchronous method invocations.
Most types take any number of members. A type member is constrained by the set {constructor, finalizer, static constructor, nested type, operator, method, property, indexer, field, read-only field, constant, event}.
The CTS defines various adornments that may be associated with a given member. For example, each member has a given visibility trait (e.g., public, private, protected). Some members may be declared as abstract (to enforce a polymorphic behavior on derived types) as well as virtual (to define a canned, but overridable, implementation). Most members can be configured as static (bound at the class level) or instance (bound at the object level).
One more aspect of the CTS is that it establishes a well-defined set of fundamental data types.
The Common Language Specification
Different programming languages obviously express the same programming constructs in different ways, e.g. string concatenation in C# uses the plus operator (+) while in VB, the ampersand (&) is used instead. These syntactic variations are inconsequential in the eyes of the .NET runtime given that the different compilers emit a similar set of CIL instructions. However, the languages have differences in their overall level of functionality, for example a .NET language may or may not have a keyword to represent unsigned data.
The CLS describes the minimal and complete set of features a given .NET compiler must support to produce code that can be hosted by the .NET Runtime. It can be viewed as a subset of the full functionality defined by the CTS. The CLS is a set of rules, each of which is assigned a simple name, for example:
Rule 1: CLS rules apply only to those parts of a type that are exposed outside the defining assembly.
Given this rule, the remaining rules do not apply to the inner workings of a .NET type. The only aspects of a type that must conform to the CLS are the member definitions themselves. The implementation logic can use non-CLS techniques.
C# defines a number of programming constructs that are not CLS compliant. The C# compiler can check your code for CLS compliance using a single .NET attribute.
The .NET Runtime
The term runtime can be understood as a collection of services that are required to execute a given compiled unit of code. For example, Java developers must ensure the Java virtual machine (JVM) has been installed on the machine in order to run their software. The .NET runtime provides a single, well-defined runtime layer that is shared by all languages and platforms that are .NET.
Namespaces
C# does not come with a language-specific code library. C# developers instead leverage the language-neutral .NET libraries. The .NET platform makes extensive use of namespaces to keep all the types within the base class libraries well organized. A namespace is a grouping of semantically related types contained in an assembly or possibly spread over multiple assembles. The System.IO namespace contains file I/O-related types, and System.Data contains basic database types. Any language targeting the .NET runtime must use the same namespaces and the same types.
System is a fundamental namespace and provides a core body of types including the core data types like System.Int32 and System.String.
In C#, the using keyword allows us to not have to use the fully qualified name. The global keyword can be used in front of the using statement to make it apply to every file in the project automatically. Global using statements can also be put in the project file. A new feature of .NET 6/C# 10 is implicit global using statements which are usually enabled by default.
Also new in C# 10, file-scoped namespaces removes the need to wrap code in braces when placing it in a custom namespace.
ildasm.exe
The Intermediate Language Disassembler utility (ildasm.exe) allows creation of a text document representing a .NET assembly and investigation of its contents including the manifest, CIL code, and type metadata. It is not necessary, but using it from time to time helps to understand the inner workings of the .NET platform and how the C# code maps to runtime concepts.
Summary
.NET basically boils down to the .NET Runtime and base class libraries. The runtime is able to host any .NET binary (assembly) that abides by the rules of managed code. Assemblies contain CIL instructions, type metadata, and a manifest.
Article notes
What has support for numerous programming languages that share a common runtime engine, language integration with cross-language inheritance, exception handling, and debugging, a comprehensive base class library, a simplified deployment model, and extensive command-line support?
.NET
.NET can be understood as what two things from a programmer's point of view?
A runtime environment and base class library
What describes all of the possible data types and programming constructs supported by the .NET runtime?
The Common Type System
What is the specification related to the Common Type System that defines the subset of common types and programming constructs that all .NET languages agree on?
The Common Language Specification
What language does C# look very similar to?
Java
What family of programming languages do both C# and Java belong to?
The C family
What term can be understood as a collection of services that are required to execute a given compiled unit of code?
Runtime
Code that targets the .NET runtime is referred to as:
Managed code
What in C#/.NET is a grouping of semantically related types contained in an assembly or possibly spread over multiple assemblies?
A namespace
What is the new C# feature which removes the need to wrap code in braces when placing it in a custom namespace?
File-scoped namespaces
What is the fundamental .NET namespace that provides a core body of types including Int32 and String?
System
What is the file extension seen in both .NET binaries and unmanaged Windows binaries (despite these having absolutely no internal similarities)?
.dll
What does the .NET platform make extensive use of to keep all the types within the base class libraries well organized?
Namespaces
The .NET base class libraries is sometimes written as what abbreviation?
BCLs
When a *.dll has been creating using a .NET compiler, what is the term for the binary blob?
An assembly
What is the metadata (that is different from and in addition to the CIL and type metadata) in a .NET assembly that describes the assembly itself?
The manifest
The set {constructor, finalizer, static constructor, nested type, operator, method, property, indexer, field, read-only field, constant, and event} describes what in general in C#?
Type members
What is the C# keyword for System.Int64 in the Common Type System?
long
What is the C# keyword for System.Single in the Common Type System?
float
By convention, all .NET interface names begin with?
I
What are the three languages that are directly supported by Microsoft and can build .NET applications?
C#, Visual Basic, and F#
What is the term for a binary blob created by a .NET compiler?
An assembly
The common intermediate language code contained in the .NET assembly is conceptually similar to what?
Java bytecode
What are the JIT compilers used by .NET sometimes called?
Jitters