Now that you know some of the major benefits provided by .NET, let’s preview three key (and interrelated)
topics that make it all possible: the CLR, CTS, and CLS. From a programmer’s point of view, .NET can be
understood as a runtime environment and a comprehensive base class library. The runtime layer is properly
referred to as the Common Language Runtime, or CLR. The primary role of the CLR is to locate, load, and
manage .NET objects on your behalf. The CLR also takes care of a number of low-level details such as
memory management, application hosting, coordinating threads, and performing basic security checks
(among other low-level details).
Another building block of the .NET platform is the Common Type System, or CTS. The CTS specification
fully describes all possible data types and all programming constructs supported by the runtime, specifies
how these entities can interact with each other, and details how they are represented in the .NET metadata
format.
Understand that a given .NET-aware language might not support every feature defined by the CTS. The
Common Language Specification, or CLS, is a related specification that defines a subset of common types
and programming constructs that all .NET programming languages can agree on. Thus, if you build .NET
types that expose only CLS-compliant features, you can rest assured that all .NET-aware languages can
consume them. Conversely, if you make use of a data type or programming construct that is outside of the
bounds of the CLS, you cannot guarantee that every .NET programming language can interact with your
.NET code library. Thankfully, as you will see later in this chapter, it is simple to tell your C# compiler to
check all of your code for CLS compliance.
The Role of the Base Class Libraries
In addition to the CLR, CTS, and CLS specifications, the .NET platform provides a base class library that
is available to all .NET programming languages. Not only does this base class library encapsulate various
primitives such as threads, file input/output (I/O), graphical rendering systems, and interaction with various
external hardware devices, but it also provides support for a number of services required by most real-world
applications.
The base class libraries define types that can be used to build any type of software application. For
example, you can use ASP.NET to build web sites and REST services, WCF to build distributed systems, WPF
to build desktop GUI applications, and so forth. As well, the base class libraries provide types to interact with
the directory and file system on a given computer, communicate with relational databases (via ADO.NET),
and so forth. From a high level, you can visualize the relationship between the CLR, CTS, CLS, and the base
class library.
What C# Brings to the Table
C# is a programming language whose core syntax looks very similar to the syntax of Java. However, calling
C# a Java clone is inaccurate. In reality, both C# and Java are members of the C family of programming
languages (e.g., C, Objective C, C++) and, therefore, share a similar syntax.
The truth of the matter is that many of C#’s syntactic constructs are modeled after various aspects of
Visual Basic (VB) and C++. For example, like VB, C# supports the notion of class properties (as opposed
to traditional getter and setter methods) and optional parameters. Like C++, C# allows you to overload
operators, as well as create structures, enumerations, and callback functions (via delegates).
Moreover, as you work through this text, you will quickly see that C# supports a number of features
traditionally found in various functional languages (e.g., LISP or Haskell) such as lambda expressions
and anonymous types. Furthermore, with the advent of Language Integrated Query (LINQ), C# supports a number of constructs that make it quite unique in the programming landscape. Nevertheless, the bulk of C#
is indeed influenced by C-based languages.
Because C# is a hybrid of numerous languages, the result is a product that is as syntactically clean
(if not cleaner) as Java, is about as simple as VB, and provides just about as much power and flexibility as C++.
Here is a partial list of core C# features that are found in all versions of the language:
- No pointers required! C# programs typically have no need for direct pointer manipulation
- Automatic memory management through garbage collection. Given this, C# does not support a delete keyword.
- Formal syntactic constructs for classes, interfaces, structures, enumerations, and delegates.
- The C++-like ability to overload operators for a custom type, without the complexity (e.g., making sure to “return *this to allow chaining” is not your problem).
- Support for attribute-based programming. This brand of development allows you to annotate types and their members to further qualify their behavior. For example, if you mark a method with the [Obsolete] attribute, programmers will see your custom warning message print out if they attempt to make use of the decorated member.
- The ability to build generic types and generic members. Using generics, you are able to build efficient and type-safe code that defines numerous placeholders specified at the time you interact with the generic item.
- Support for anonymous methods, which allow you to supply an inline function anywhere a delegate type is required.
- The ability to define a single type across multiple code files (or, if necessary, as an in-memory representation) using the partial keyword.
- Support for strongly typed queries (e.g., LINQ) used to interact with various forms of data.
- Support for anonymous types that allow you to model the structure of a type (rather than its behavior) on the fly in code.
- The ability to extend the functionality of an existing type (without subclassing) using extension methods.
- Inclusion of a lambda operator (=>), which even further simplifies working with .NET delegate types.
- A new object initialization syntax, which allows you to set property values at the time of object creation.
- Support for optional method parameters, as well as named method arguments.
- Support for dynamic lookup of members at runtime via the dynamic keyword. this provides a unified approach to invoking members on the fly, regardless of which framework the member implemented.
- Working with generic types is much more intuitive, given that you can easily map generic data to and from general System.Object collections via covariance and contravariance.
C# 6 was released with .NET 4.6 and introduced a number of minor features that help streamline your
codebase. Here are is a quick rundown of some of the features found in C# 6:
- Inline initialization for automatic properties as well as support for read-only automatic properties
- Single-line method implementations using the C# lambda operator
- Support of static imports to provide direct access to static members within a namespace
- A null conditional operator, which helps check for null parameters in a method implementation
- A new string-formatting syntax termed string interpolation
- The ability to filter exceptions using the new when keyword
- Using await in catch and finally blocks
- nameOf expressions to return a string representation of symbols
- Index initializers
- Improved overload resolution
- Declaring out variables as inline arguments
- Nesting functions inside other functions to limit scope and visibility
- Additional expression-bodied members
- Generalized async return types
- New tokens to improve readability for numeric constants
- Lightweight unnamed types (called tuples) that contain multiple fields
- Updates to logic flow using type matching in addition to value checking (pattern matching)
- Returning a reference to a value, instead of just the value itself (ref locals and returns)
- The introduction of lightweight throwaway varials (called discards)
- Throw expressions, allowing the throw to be executed in more places, such as conditional expressions, lambdas, and others
- The ability to have a program’s main method be async
- A new literal, default, that allows for initialization of any type.
- Correction of an issue with pattern matching that prevented using generics with the new pattern matching feature.
- Like anonymous methods, tuple names can be inferred from the projection that creates them.
It is important to note that the C# language can be used only to build software that is hosted under the .NET
runtime (you could never use C# to build a native COM server or an unmanaged C/C++-style application).
Officially speaking, the term used to describe the code targeting the .NET runtime is managed code. The
binary unit that contains the managed code is termed an assembly (more details on assemblies in just a bit).
Conversely, code that cannot be directly hosted by the .NET runtime is termed unmanaged code.
As mentioned previously (and detailed later in this chapter and the next), the .NET platform can run
on a variety of operating systems. Thus, it is quite possible to build a C# application on a Windows machine
using Visual Studio and run the program on a macOS machine using the .NET Core runtime. As well, you
could build a C# application on Linux using Xamarin Studio and run the program on Windows, macOS and
so on. With the most recent release of Visual Studio 2017, you can also build .NET Core applications on a
Mac to be run on Windows, macOS or Linux. To be sure, the notion of a managed environment makes it
possible to build, deploy, and run .NET programs on a wide variety of target machines.
Comments
Post a Comment