NET Programming Notes
NET Programming Notes
* .NET Runtime
5 Categories of Types
- Classes
- Structures
- Enumerations
- Interfaces
- Delegates
* .NET Standar
* C# 10
Record structs
Unmanaged code can still be accessed from a C# program, but it then locks you
into a specific development and deployment target.
Regardless of which .NET language you choose to program with, understand that
despite .NET binaries taking the same file extension as unmanaged Windows binaries
(*.dll), they have absolutely no internal similarities. Specifically, .NET binaries
do not contain platform-specific instructions but rather platform- agnostic
Intermediate Language (IL) and type metadata
First, unlike .NET Framework assemblies that can be either a *.dll or *.exe, .NET
projects are always compiled to a file with a .dll extension, even if the project
is an executable. Executable .NET assemblies
are executed with the command dotnet <assembly name>.dll. New in .NET Core 3.0 (and
later), the dotnet.exe command is copied to the build directory and renamed to
<assembly name>.exe. Running this command automatically calls the dotnet <assembly
name>.dll file, executing the equivalent of dotnet <assembly name>.dll. The *.exe
with your project name isn’t actually your project’s code; it is a convenient
shortcut to running your application.
Finally, in addition to CIL and type metadata, assemblies themselves are also
described using metadata, which is officially termed a manifest. The manifest
contains information about the current version of the assembly, culture information
CIL code must be compiled on the fly before use. The entity that compiles CIL code
into meaningful CPU instructions is a JIT compiler, which sometimes goes by the
friendly name of jitter. The .NET runtime environment leverages a JIT compiler for
each CPU targeting the runtime, each optimized for the underlying platform.
Now that you have previewed each of the types formalized by the CTS, realize that
most types take any number of members. Formally speaking, 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). Also, most members may be configured as static (bound at the class
level) or instance (bound at the object level).
The CLS is ultimately a set of rules that compiler builders must conform to if they
intend their products to function seamlessly within the .NET universe
Rule 1: CLS rules apply only to those parts of a type that are exposed outside the
defining assembly.
* .NET Runtime
- using System;
While defining a type using the fully qualified name provides greater readability,
I think you’d agree that the C# using keyword reduces keystrokes. In this text, we
will avoid the use of fully qualified names (unless there is a definite ambiguity
to be resolved) and opt for the simplified approach of the C# using keyword.
However, always remember that the using keyword is simply a shorthand notation for
specifying a type’s fully qualified name, and either approach results in the same
underlying CIL (given that CIL code always uses fully qualified names) and has no
effect on performance or the size of the assembly.
As you build more complex C# applications, you will most likely have namespaces
repeated in multiple files. Introduced in C# 10, namespaces can be referenced
globally, and then be available in every file in the project automatically. Simply
add the global keyword in front of your using statements, like this:
global using System;
<ItemGroup>
<Using Include=”System.Text” />
<Using Include=”System.Text.Encodings.Web” />
<Using Include=”System.Text.Json” />
<Using Include=”System.Text.Json.Serialization” />
</ItemGroup>
Another new feature included with .NET 6/C# 10 are implicit global using
statements. The implicit global using statements supplied by .NET 6 varies based on
the type of application you are building.
Also new in C# 10, file-scoped namespaces remove the need to wrap your code in
braces when placing
it in a custom namespace. Take the following example of the Calculator class,
contained in the CalculatorExamples namespace. Prior to C# 10, to place a class in
a namespace required the namespace declaration, an opening curly brace, the code
(Calculator), and then a closing curly brace. In the example, the extra code is in
bold:
namespace CalculatorExamples
{
class Calculator()
{
...
}
}
As your code becomes more complex, this can add a lot of extra code and
indentation. With file scoped namespaces, the following code achieves the same
effect:
namespace CalculatorExamples
class Calculator()
{
...
}
Prior versions of the .NET Framework used a common installation location for
framework libraries known as the Global Assembly Cache (GAC). Instead of having a
single installation location, .NET does not use the GAC. Instead, each version
(including minor releases) is installed in its own location (by version) on the
computer
For an assembly to have access to another assembly that you are building (or
someone built for you), you need to add a reference from your assembly to the other
assembly and have physical access to the other assembly. Depending on the
development tool you are using to build your .NET applications, you will have
various ways to inform the compiler which assemblies you want to include during the
compilation cycle.