Pro C# 10 with .NET 6 Chapter 1. Introducing C# and .NET 6 Study cards

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.
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 can be understood as what two things from a programmer's point of view?
What describes all of the possible data types and programming constructs supported by the .NET runtime?
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?
What language does C# look very similar to?
What family of programming languages do both C# and Java belong to?
What term can be understood as a collection of services that are required to execute a given compiled unit of code?
Code that targets the .NET runtime is referred to as:
What in C#/.NET is a grouping of semantically related types contained in an assembly or possibly spread over multiple assemblies?
What is the new C# feature which removes the need to wrap code in braces when placing it in a custom namespace?
What is the fundamental .NET namespace that provides a core body of types including Int32 and String?
What is the file extension seen in both .NET binaries and unmanaged Windows binaries (despite these having absolutely no internal similarities)?
What does the .NET platform make extensive use of to keep all the types within the base class libraries well organized?
The .NET base class libraries is sometimes written as what abbreviation?
When a *.dll has been creating using a .NET compiler, what is the term for the binary blob?
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 set {constructor, finalizer, static constructor, nested type, operator, method, property, indexer, field, read-only field, constant, and event} describes what in general in C#?
What is the C# keyword for System.Int64 in the Common Type System?
What is the C# keyword for System.Single in the Common Type System?
By convention, all .NET interface names begin with?
What are the three languages that are directly supported by Microsoft and can build .NET applications?
What is the term for a binary blob created by a .NET compiler?
The common intermediate language code contained in the .NET assembly is conceptually similar to what?
What are the JIT compilers used by .NET sometimes called?
Pro C# 10 with .NET 6 Chapter 2. Building C# Applications Study cards
To get started developing applications with C# 10 and .NET 6, the .NET 6 SDK needs to be installed; this also installs the .NET 6 runtime.

To confirm the installation, open a command window and use the .NET command-line interface dotnet.exe. The --version option displays the highest version of the SDK installed on your machine, or the version specified in a global.json location at or above your current directory (dotnet --version).

Use dotnet --list-runtimes to show all of the .NET Core Runtimes installed on your machine. There is Microsoft.AspNetCore.App for building ASP.NET Core applications, Microsoft.NETCore.App which is the foundational runtime for .NET, and Microsoft.WindowsDesktop.App for building WinForms and WPF applications.

Use dotnet --list-sdks to show all of the SDKs installed.

New with .NET 6 is a command to check the installed versions and runtimes for updates (dotnet sdk check).

To pin your project to using an earlier version of the .NET SDK, you can use a global.json file.

For this book, you will want to install Visual Studio 2022 Community with the .NET desktop development, ASP.NET and web development, and Data storage and processing workloads. You should also select Class Designer and Git for Windows under "Code tools" on the "Individual components" tab before you click Install.

Visual Studio 2022 is a complete IDE for software development using .NET and C#. You can easily create a new console app through the "Create a new project" option and choosing the Console app template. Visual Studio also gives you the ability to design classes and other types (such as interfaces or delegates) in a visual manner.

{{c1::Visual Studio Code}} is a popular IDE by Microsoft (in addition to Visual Studio 2022) that is fast with limited functionality that can be customized through extensions.

To restore and build all the projects in your solution: dotnet build

To run your project without debugging: dotnet run
What do you also get, that you might install separately, when you install the .NET SDK?
What is the command to list all the .NET runtimes installed on your machine?
What is the command to list all the .NET SDKs that are installed?
What's the first thing to install to get started developing applications with C# and .NET?
What long option to the dotnet command will display the .NET SDK version in use?
What long option to the dotnet command will display the installed runtimes?
What long option to the dotnet command will display the installed SDKs?
What in .NET terminology can contain multiple projects that all work together?
What is the dotnet CLI command to restore all of the NuGet packages required for your solution?
What is the dotnet runtime for building ASP.NET Core applications?
What is the dotnet runtime that is the foundational runtime for .NET?
What is the node in the *.csproj file that sets the .NET version?
What is the dotnet command to check for updates for your installed versions of the .NET SDK and runtimes?
What file can you put in a .NET project to make dotnet.exe --version in that directory (and any subdirectory) pinned to something?
[...] is a popular IDE by Microsoft (in addition to Visual Studio 2022) that is fast with limited functionality that can be customized through extensions.
Pro C# 10 with .NET 6 Chapter 3. Core C# Programming Constructs, Part 1 Study cards

Breaking Down a Simple C# Program


C# demands that all program logic be contained within a type definition. Recall that a type is a general term referring to a member of the set {class, interface, structure, enumeration, delegate}. In C#, it is not possible to create global functions or global points of data. All data members and all methods must be contained within a type definition.

Prior to C# 10, you were required to write the following to print "Hello World" to the standard console output window:

using System;

namespace SimpleCSharpApp
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Hello World");
    }
  }
}

Now in C# 10, it can be done with one line of code:

Console.WriteLine("Hello World");

The Console class is contained in the System namespace. With the implicit global namespaces provided by .NET 6/C# 10, the using System; statement is no longer needed. Both the namespace and Program class can be removed due to the top-level statement functionality introduced in C# 9.

Note: all C# keywords are lowercase, while namespaces, types, and member names begin by convention with an initial capital letter and the first letter of any embedded words is capitalized.

class Program
{
  static void Main(string[] args)
  {
    // Display a simple message to the user
    Console.WriteLine("***** My First C# App *****");
    Console.WriteLine("Hello World");
    Console.WriteLine();

    // Wait for Enter to be pressed before shutting down
    Console.ReadLine();
  }
}

By default, the C# project templates that do not use top-level statements name the class containing the Main() method Program but you can change this if you want. Prior to C# 9, every executable C# application must contain a class defining a Main() method which signifies the entry point of the application.

Formally, the class that defines the Main() method is termed the application object. It is possible for a single executable application to have more than one application object. In this case, the compiler must known which Main() method should be used as the entry point. For now, also note that static members are scoped to the class level rather than the object level. This means that they can be invoked without the need to create a new instance of the class.

This Main() method also takes an array of strings which can contain any number of incoming command-line arguments. By not explicitly defining a return value, this Main() method has been setup to return a void return value.

Among the members of the Console class are WriteLine() and ReadLine(). WriteLine() sends a text string and carriage return to the standard output. Console.ReadLine() ensures that the command prompt launched by the Visual Studio IDE remains visible, but note that this would be the default anyway when running .NET Core Console apps with Visual Studio.

Using Top-Level Statements


Top-level statements which were introduced by C# 9.0 eliminate much of the ceremony around the C# application's entry point. There are some rules around top-level statements. Only one file in the app can use them. When using them, the program cannot have a declared entry point. They cannot be enclosed in a namespace. They can still access a string array of args. Top-level statements return an application code by using a return. Functions that would have been declared in the Program class become local functions for the top-level statements. The top-level statements compile for a class named Program. This allows for the addition of a partial Program class to hold regular methods. Additional types can be declared after all top-level statements. Trying to declare a type before the end of the top-level statements will cause a compilation error.

Specifying an Application Error Code


The vast majority of Main() methods will return void. However, C# is consistent with other C-based languages with the ability to return an int. By convention, returning a 0 indicates success. 0 is automatically returned even if the Main() method is prototyped to return void. A different value, such as -1, represents an error condition. When using top-level statements, if the executing code returns an integer, then that is the return code. If nothing is explicitly returned, it still returns 0.

The application's return value is passed to the system at the time the application terminates. A script can be used to run the app and capture the return value. Note that the vast majority of Main() will use void as the return value which implicitly returns the error code of 0.

Processing Command-Line Arguments


// Display a message and wait for Enter key to be pressed.
Console.WriteLine("My First C# App");
Console.WriteLine("Hello world");
Console.WriteLine();
// Process any incoming args.
for (int i = 0; i < args.Length; i++)
{
  Console.WriteLine("Arg: {0}", args[i]);
}
Console.ReadLine();
// Return an arbitrary error code.
return 0;

This example is using top-level statements. If the generated IL for the program is inspected, the <Main>$ method accepts a string array named args. If the program is using a Main() method as the entry point, then the method signature must accept a string array of args:

static int Main(string[] args)
{
...
}

As an alternative to the standard for loop, you can also iterate over an incoming string array using the foreach keyword.

foreach(string args in args)
{
  Console.WriteLine("Arg: {0}", arg);
}
Console.ReadLine();
return 0;

You are also able to access command-line arguments using the static GetCommandLineArgs() method of the System.Environment type. This returns an array of strings. The first entry will be the name of the application itself and the rest of the elements are the individual command-line arguments.

string[] theArgs = Environment.GetCommandLineArgs();
foreach(string arg in theArgs)
{
  Console.WriteLine("Arg: {0}", arg);
}
Console.ReadLine();
return 0;

Note that the GetCommandLineArgs method does not receive the arguments for the application through the Main() method and does not depend on the string[] args parameter.

Specifying Command-Line Arguments with Visual Studio 2022


Note you can do this for testing and debugging purposes in development.

Additional Members of the System.Environment Class


The Environment class exposes a number of extremely helpful methods beyond GetCommandLineArgs(). It lets you get details regarding the operating system currently hosting the app and other things.

Using the System.Console Class


The Console class encapsulates input, output, and error-stream manipulations for console-based applications.



Performing Basic Input and Output (I/O) with the Console Class


The Console type defines a set of methods to capture input and output. All of these are static and therefore prefixed by the name of the class. WriteLine() pumps a text string (including a carriage return) to the output system. Write() does this without a carriage return. ReadLine() allows you to receive information from the input stream up until the Enter key is pressed. Read() is used to capture a single character from the input stream.

static void GetUserData()
{
  Console.Write("Please enter your name: ");
  string userName = Console.ReadLine();
  Console.Write("Please enter your age: ");
  string userAge = Console.ReadLine();

  ConsoleColor prevColor = Console.ForegroundColor;
  Console.ForegroundColor = ConsoleColor.Yellow;

  Console.WriteLine("Hello {0}! You are {1} years old.",
  userName, userAge);

  Console.ForegroundColor = prevColor;
}

Formatting Console Output


.NET 6 supports a style of string formatting slightly similar to the printf() statement of C. When you are defining a string literal that contains segments of data whose value is not known until runtime, you are able to specify a placeholder within the string literal using the curly-bracket syntax. At runtime, the values passed into Console.WriteLine() are substituted for each placeholder. Note that if you have more uniquely numbered curly-bracket placeholders than fill arguments, you will get a format exception at runtime. But if there are too many fill arguments, the unused ones are ignored. You can also repeat the same placeholder in a given string. An alternative way to format strings is string interpolation.

Formatting Numerical Data




Console.WriteLine("c format: {0:c}", 99999);
Console.WriteLine(f3 format: {0:f3}", 99999);

Formatting Numerical Data Beyond Console Applications


The same formatting syntax can be used with the string.Format() method which returns a new String object.

string userMessage = string.Format("10000 in hex is {0:x}", 10000);

Working with System Data Types and Corresponding C# Keywords


C# defines keywords for fundamental data types which are used to represent local variables, class data member variables, method return values, and parameters. The C# data type keywords are shorthand notations for types in the System namespace. Not all of the types are compliant with the Common Language Specification.



Understanding Variable Declaration and Initialization


To declare a local variable, specify the type followed by the variable's name.

If you make use of a local variable before assigning an initial value, it will result in a compiler error. Thus it is a good practice to assign an initial value at the time of declaration. You can declare and initialize the variable on the same line or you can separate it into two code statements.

You can also declare multiple variables of the same type on one line:

bool b1 = true, b2 = false, b3 = b1;

The C# bool keyword is a shorthand notation for the System.Boolean structure. You can also declare variables using the full name of the type:

System.Boolean b4 = false;

The default Literal


default is a literal that assigns a default value for the data type:

int myInt = default;

Using Intrinsic Data Types and the new Operator


All intrinsic data types support what is known as the default constructor. This lets you create a variable using the new keyword. The new keyword automatically sets the variable to its default value.

bool variables are set to false. Numeric data is set to 0 or 0.0 if it is a floating-point type. char variables are set to a single empty character. BigInteger variables are set to 0. Object references (including strings) are set to null.

bool b = new bool();

C# 9.0 added a shortcut for creating variable instances:

bool b = new();

Understanding the Data Type Class Hierarchy


Even the primitive .NET data types are arranged in a class hierarchy.



Ultimately, each type if derived from System.Object. This defines a set of methods common to all types in the .NET Core base class libraries including ToString(), Equals(), and GetHashCode().

Note that many numerical types derive from a class called ValueType. Descendents of ValueType are automatically allocated on the stack, and therefore, have a predictable lifetime and are quite efficient. Types that do not have System.ValueType are instead allocated on the garbage-collected heap.

Understanding the Members of Numerical Data Types


The numerical types of .NET Core support MaxValue and MinValue properties that provide the range a given type can store. Some types also have other members.

Understanding the Members of System.Boolean


The only valid assignment a C# bool can take is from the set true and false. It supports TrueString and FalseString properties.

Understanding the Members of System.Char


Both System.String and System.Char are Unicode under the hood.

Parsing Values from String Data


A form of parsing is generating a variable of a type given a textual equivalent and is supported by the .NET data types.

bool b = bool.Parse("True");

Using TryParse to Parse Values from String Data


Note that this will fail at runtime:

bool b = bool.Parse("Hello");

It can be wrapped in a try-catch block or a TryParse() statement. TryParse() takes an out parameter and returns a bool if the parsing was successful.

Using System.DateTime and System.TimeSpan


The System namespace also defines a few useful types that do not have C# keywords. For example, DateTime which contains data that represents a specific date and time value and TimeSpan which allows you to easily define and transform units of time using various members.

Working with the System.Numerics Namespace


This namespace defines a structure called BigInteger. It also has a structure called Complex.

If you need to define a massive numerical value, the first step is to add the following using directive:

using System.Numerics;

Note a BigInteger variable cannot be changed as the data is immutable.

Using Digit Separators


The _ was introduced as a digit separator in C# 7.0 for integer, long, decimal, double data, and hex types.

Console.Write(123_456.12);

Using Binary Literals


C# 7.0 also introduced a new literal for binary values that could be used to create bit masks for example.

Console.WriteLine(0b_0001_0000);

Working with String Data




Be aware that a few members of System.String are static and therefore called at the class level.

Note strings are immutable and so methods like Replace() actually are returning a new string.

Performing String Concatenation


string s3 = s1 + s2;

The C# + symbol here is processed by the compiler to emit a call to the static String.Concat() method.

string s3 = String.Concat(s1, s2);

Using Escape Characters


C# string literals may contain various escape characters which qualify how the character data should be printed to the output stream. Each begins with a backslash.



Performing String Interpolation


String interpolation, using string literals that contain placeholders for variables, was introduced by C# 6.0.

Performance Improvements


String handling has improved performance in C# 10 when your code contains string interpolation.

Defining Verbatim Strings


A string prefixed with the @ symbol is what is known as a verbatim string. This disables the processing of the literal's escape characters.

Working with Strings and Equality


A reference type is an object allocated on the garbage-collected managed heap. By default, when you perform a test for equality on reference types (== and !=) it will return true if the references are pointing to the same object in memory. Even though the string data type is a reference type, the equality operators were redefined to compare the values of the string objects.

Modifying String Comparison Behavior




Strings Are Immutable


After a string object is assigned a value, the value cannot be changed. Methods of the string type simply return a new string. The string class can be inefficient and result in bloated code if misused especially when performing string concatenation or working with huge amounts of text data.

Using the System.Text.StringBuilder Typer


The .NET Core base class libraries provide the System.Text namespace to solve some of the performance issues of the string type when it is used with reckless abandon.

using System.Text;

Constructors allow you to create an object with an initial state when you apply the new keyword and there are several that create instances of StringBuilder. Members of the StringBuilder type modify the object's internal character data which makes it more efficient.

StringBuilder sb = new StringBuild("*****");
sb.Append("\n");

Narrowing and Widening Data Type Conversions


short numb1 = 9, numb2 = 10;
Console.WriteLine("{0} + {1}",
  numb1, numb2, Add(numb1, numb2));
Console.ReadLine();

static int Add(int x, int y)
{
  return x + y;
}

Add() expects two int arguments but it was called with two short variables. The program compiles and executres without error because there is no possibility for loss of data. The maximum range of a short is well within the maximum range of an int. The compiler implicitly widens each short to an int.

Formally speaking, widening is the term used to define an implicit upward cast that does not result in a loss of data.

 Narrowing is the opposite. All narrowing converstions result in a compiler error. If you want to tell the compiler that you are willing to deal with a possible loss of data because of a narrowing operation, you must apply an explicit cast using the C# casting operator, ().

short answer = (short)Add(numb1, numb2);

An explicit cast allows you to force the compiler to apply a narrowing conversion and may result in an incorrect value.

Using the checked Keyword


The checked keyword can wrap a statement or a block of statements. Within the scope of checked, additional CIL instructions will test for overflow conditions. If an overflow occurs, it will result in a runtime exception: System.OverflowException.

byte sum = checked((byte)Add(b1, b2));

Setting Project-wide Overflow Checking


This can be set for the entire project with configuration of the project file. All arithmetic can be evaluated for overflow without the need to use the checked keyword. It can also be configured through Visual Studio.

Using the unchecked Keyword


The unchecked keyword can be used if you want to have a block of code where data loss is acceptable after you have done the above.

Understanding Implicitly Typed Local Variables


Many would argue it is generally a good practice to explicitly specify the data type of every variable. The C# language does however provide for implicitly typing using the var keyword. The var keyword can be used in place of specifying a data type. The compiler will automatically infer the underlying data type based on the initial value used to initialize the data point. You can verify that the types have been set correctly using reflection, which is the act of determining the composition of a type at runtime.

Console.WriteLine("myString is a: {0}", myString.GetType().Name);

Note you can use implicit typing for any type.

Declaring Numerics Implicitly


Whole numbers default to integers. Floating-point numbers default to doubles.

Understanding Restrictions on Implicitly Typed Variables


There are some restrictions to using var. First, implicit typing applies only to local variables in a method or property scope. It is illegal to use var to define return values, parameters, or field data of a custom type.

class ThisWillNeverCompile
{
  // Error!
  private var myInt = 10;

  // Error!
  public var MyMethod(var x, var y){}
}

Also, local variables declared using var must be assigned an initial value. They cannot be assigned the initial value of null. It is permissible to assign an inferred local variable to null after its initial assignment provided it is a reference type.

Implicitly Typed Data is Strongly Typed Data


Be aware that implicit typing of local variables results in strongly typed data. Therefore the use of var is not the same technique when used with scripting languages (Javascript, Perl) or the COM Variant data type, where a variable can hold values of different types over its lifetime in a program (called dynamic typing). Note C# does allow for dynamic typing through the dynamic keyword.

Understanding the Usefulness of Implicitly Typed Local Variables


Using var to declare local variables simply for the sake of doing so brings little to the table. It can make reading the code more confusing as it becomes harder to quickly determine the underlying data type. If you know you need an int, declare an int!

The LINQ technology set makes use of query expressions that can yield dynamically created result sets based on the format of the query itself. Implicit typing is extremely helpful in these cases as you do not need to explicitly define the type that a query may return, which in some cases would be impossible to do. When you are using LINQ, you seldom if ever care about the underlying type of the query's return value. It could be argued that the only time you would make use of the var keyword is when defining data returned from a LINQ query. Overuse of implicit typing (via the var keyword) is considered by most developers to be poor style in production code.

Working with C# Iteration Constructs


C# provides these iteration constructs: for loop, foreach/in loop, while loop, do/while loop.

for(int i = 0; i < 4; i++)
{
  Console.WriteLine("Number is: {0} ", i);
}


string[] carTypes = {"Ford", "BMW", "Yugo", "Honda"};
foreach (string c in carTypes)
{
  Console.WriteLine(c);
}

// LINQ query!
var subset = from i in numbers where i < 10 select i;

foreach (var i in subset)
{
  Console.Write("{0} ", i);
}

while(userIsDown.ToLower() != "yes")
{
...
}


do/while are similar to while loops but are guaranteed to execute the corresponding block of code at least once.

A Quick Discussion About Scope


A scope is created uysing curly braces. It is allowed to not use curly braces, but typically it is not a good idea.

Working with Decision Constructs and the Relational/Equality Operators


C# defines two simple constructs to alter the flow of your program: if/else and switch.

Unlike in C and C++, the if/else statement in C# operates only on Boolean expressions.

New in C# 7.0, pattern matching is allowed in if/else statements.

The conditional operator (?:) also known as the ternary conditional operator is a shorthand of writing a simple if/else statement. There are some limitations: both expressions must have an implicit conversion to a target type, and it can only be used in assignment statements.

Using Logical Operators


&&, ||, !

Note that && and || short-circuit. & and | can be used instead if you require all expressions to be tested regardless.

Using the switch Statement


The switch statement can evaluate many different types. If multiple case statements should produce the same result, they can be combined. The switch statement also supports goto as a way to exit a case condition, but it should not be used generally. The switch can also be done on the type of a variable being checked.

Using switch Expressions


static string FromRainbow(string colorBand)
{
  return colorBand switch
  {
    "Red" => "FF0000",
    "Orange" => "FF7F00",
    _ => "#FFFFFF",
  };
}

Tuples can be used to compare more than one value during a switch statement:

static string RockPaperScissors(string first, string second)
{
  return (first, second) switch
  {
    ("rock", "paper") => "Paper wins.",
    ...
    (_, _) => "Tie.",
  };
}

Summary


The goal of this chapter was just to expose you to numerous aspects of the C# programming language. Every C# executable program must have a type defining a Main() method either explicitly or implicitly through the use of top-level statements. Each data type keyword (e.g. int) is really a shorthand notation for a full-blown type in the System namespace. Given this, each C# data type has a number of built-in members.

The most useful place for implicit typing (using var) is when working with the LINQ programming model.

The next chapter completes the examination of core language features. After that will be the object-oriented features.
What in C# is a general term referring to a member of the set {class, interface, structure, enumeration, delegate}?
C# demands that all program logic be contained within a what?
What is missing from this list of things that are each considered a type in C#? interface, structure, enumeration, delegate
What is missing from this list of things that are each considered a type in C#? class, structure, enumeration, delegate
What is missing from this list of things that are each considered a type in C#? class, interface, enumeration, delegate
What is missing from this list of things that are each considered a type in C#? class, interface, structure, delegate
What is missing from this list of things that are each considered a type in C#? class, interface, structure, enumeration
How do you create a global function or point of data in C#?
What is the namespace that contains the C# Console class?
using System; What feature made it so that this statement is no longer needed to write a simple C# hello world program?
What using statement is no longer needed to write a hello world program in C# with the new implicit global namespaces?
What is an example of iterating through a string array (called args) using the foreach keyword in C#?
What is an example (C#) of iterating through a string array (called args) using a standard for loop?
What is the case convention for all C# keywords?
What is the case convention for all namespaces, types, and member names in C#?
What relatively new feature of C# can be used to eliminate much of the ceremony around the C# application's entry point?
When not using top-level statements, what conventionally is the name for the class that includes the Main() method in a C# program?
What method signifies the entry point of a C# application, and prior to C# 9 which introduced the top-level statement functionality, was required in every C# app?
What term refers to the class that defines the Main() method in a C# app?
What member of the C# Console class sends a text string and a carriage return to the standard output?
How many files in a C# app are allowed to use top-level statements?
What can a C# Main() method do (if you want) to specify an application error code (or code that indicates success)?
By convention, what integer returned by an app indicates success?
What is the C# Console method which is similar to WriteLine() but does not append a carriage return to the end of the text string it outputs?
What type in C# defines a set of static methods to do basic I/O?
What is the C# Console method which allows you to receive information from the input stream up until the Enter key is pressed?
What is the C# Console method that can be used to capture a single character from the input stream?
Does using the var keyword in C# result in dynamic typing?
The C# Console methods that capture input and output are all called by being prefixed with the name of the class because they are what type of methods?
What are the 2 steps to declare a local variable in C#?
At one point is it a good practice to assign an initial value to a declared variable in a language like C#?
What C# keyword is a shorthand notation for System.Int32?
How many bits is an int in C#?
How many bits is a uint in C#?
How many bits is a short in C#?
How many bits is a ushort in C#?
How many bits is a long in C#?
What C# keyword is a shorthand notation for System.Int16?
What is the highest value that a variable of type ushort can have in C#?
What is the lowest value that a variable of type sbyte can have in C#?
What is the highest value that a variable of type sbyte can have in C#?
What is the highest value that a variable of type byte can have in C#?
What C# keyword is a shorthand notation for System.Boolean?
What type in the C# System namespace has the shorthand notation float?
What type in the C# System namespace has the shorthand notation double?
What C# literal can be used to assign a default value for the data type?
What is the keyword used in C# when declaring a variable using the default constructor?
What is the ultimate base class of all C# types?
Can a class derive from ValueType in C#?
What creates a scope in C#?
What class in C# defines a set of methods common to all types in the .NET Core base class libraries including ToString(), Equals(), and GetHashCode()?
Where are types that descend from ValueType (of which many numerical types derive from) allocated?
What word describes generating a variable of a type given a textual equivalent?
What can be used as a digit separator character in C#?
What is an example of what you might want to do using literal binary values like 0b_0001_0000 in C#?
What is the property in C# that returns the length of the current string?
What are the characters in C# called that when present in string literals, qualify how the character data should be printed to the output stream?
What is the escape character in C# that inserts a double quote into a string literal?
What is the escape character in C# that inserts a single quote into a string literal?
What is the escape character in C# that inserts a backslash into a string literal?
What is the escape character in C# that inserts a horizontal tab into a string literal?
What programming feature involves a string literal containing placeholders for values?
What is a string that is prefixed with the @ symbol in C# known as?
What character can a string be prefixed with in C# that will disable the processing of the string literal's escape characters?
Where are reference types allocated in C#?
When a test for equality on reference types is performed in C# (== and !=) what is the condition for == to return true?
Since methods called on strings in C# return new strings, we can say that strings are what?
What properties of numerical types in .NET Core can be used to determine the range a given type can store?
What is the C# namespace that defines BigInteger?
What is the C# namespace that defines Complex?
What refers to an implicit upward cast that does not result in a loss of data (e.g. Add() expects two int arguments but it can be called with two shorts because there is no possibility for data loss)?
What is the property in C# that returns the length of the current string?
What method in C# is analogous to upcase in Ruby?
What method in C# is analogous to downcase in Ruby?
What is the C# casting operator?
What is the act of determining the composition of a type at runtime?
What does using var to declare local variables in C# simply for the sake of doing so bring to the table?
It might be argued that the only time to use the var keyword in C# is when?
How is a scope created in C#?
Do && and || short-circuit in C#?
Do & and | short-circuit in C#?
What language construct/keyword in C# and other C-based languages allows you to handle program flow based on a predefined set of choices?
What statement in C# takes a string and an out parameter, parses the string and assigns the parsed value to the out variable, and returns true if successful?
An object allocated on the garbage-collected managed heap in C# is what kind of type in general?
How is a scope created in C, C#, Java, and other languages based on C?
When using the C# operators like == and != with reference types, when would a test for equality return true?
What enum in C# has values which can be used by overloads of methods like Equals() and Compare() to control how the comparisons are done with respect to things like culture?
What can we say about strings in C# that describes this: once a string object is assigned an initial value, the character data cannot be changed?
Pro C# 10 with .NET 6 Chapter 4. Core C# Programming Constructs, Part 2 Study cards

Understanding C# Arrays


An array is a set of contiguous data points of the same type. When declaring a C# array using this syntax, the number used in the array declaration represents the total number of items, not the upper bound:

static void SimpleArrays()
{
  Console.WriteLine("=> Simple Array Creation.");
  // Create and fill an array of 3 integers
  int[] myInts = new int[3];
  // Create a 100 item string array, indexed 0 - 99
  string[] booksOnDotNet = new string[100];
  Console.WriteLine();
}

Note also that the lower bound of the array always begins at 0.

myInts[0] = 100;
myInts[1] = 200;

Note also that if you declare an array but do not explicitly fill each index, each item will be set to the default value of the data type. For bools, that is false, and for ints, it is 0.

Looking at the C# Array Initialization Syntax


The C# array initialization syntax specifies each array item within the scope of curly brackets. This is good for when you are creating an array of a known size and want to quickly specify the initial values.

string[] stringArray = new string[] { "one", "two", "three" };
bool[] boolArray = { false, false, false };
int[] intArray = new int[4] { 20, 22, 23, 0 };

Understanding Implicitly Typed Local Arrays


The var keyword can also be used to define implicitly typed local arrays.

var a = new[] { 1, 10, 100, 1000 };

Defining an Array of Objects


System.Object is the ultimate base class to every type, including the fundamental data types. If you were to define an array of System.Object data types, then the subitems can be anything.

Working with Multidimensional Arrays


A rectangular array is simply an array of multiple dimensions where each row is of the same length. A jagged array contains some number of inner arrays but each may have a different upper limit.

int[,] myMatrix;
int[][] myJagArray = new int[5][];

Using Arrays As Arguments or Return Values


Arrays can be passed as an argument or received as a member return value.

Using the System.Array Base Class




Many members of System.Array are defined as static members (Array.Sort(), Array.Reverse()). Others such as Length are bound at the object level.

Using Indices and Ranges


System.Index represents an index into a sequence. System.Range represents a subrange of indices.

^ is the index from end operator and specifies that the index is relative to the end of the sequence. The range operator .. specifies the start and end of a range as its operands.

Understanding Methods


Methods are defined by an access modifier and return type (or void for no return type) and may or may not take parameters. A method that returns a value to the caller is commonly referred to as a function. Methods that do not return a value are commonly referred to as methods.

// Recall that static methods can be called directly
// without creating a class instance.
// static returnType MethodName(parameter list) { /* Implementation */ }
static int Add(int x, int y)
{
  return x + y;
}

Understanding Expression-Bodied Members


C# 6 introduced expression-bodied members that shorten the syntax for single-line methods:

static int Add(int x, int y) => x + y;

This is an example of syntactic sugar (the generated IL is no different). The => operator is a lambda operation but for now can be thought of as a shortcut to writing single-line statements.

Understanding Local Functions


C# 7.0 introduced being able to create methods within methods. These are officially referred to as local functions. A local function is a function declared inside another function that must be private and does not support overloading. With C# 8, they can be static. Local functions also support nesting, so a local function can have a local function inside it.

Understanding Method Parameters


Method parameters are used to pass data into a method call.

Understanding Method Parameter Modifiers


The default way a parameter is sent into a function is by value. This means that a copy of the data is passed into the function. Exactly what is copied will depend on if the parameter is a value type or reference type. Parameter modifiers can be used to control how arguments are passed to a method.



Understanding the Default Parameter-Passing Behavior


The default behavior for value types it to pass in the parameter by value and the default for reference types is to pass in the parameter by reference.

The Default Behavior for Value Types


The default way a value type parameter is sent into a function is by value. A copy of the data is passed into the function. Numerical data types are value types.

The Default Behavior for Reference Types


The default way a reference type parameter is sent into a function is by reference for its properties, but by value for itself. The string type is a special case. It is technically a reference type but it is still passed by value when the parameter does not have a modifier.

Using the out Modifier


Methods that have been defined to take output parameters (via the out keyword) are under obligation to assign them to an appropriate value before exiting the method scope.

static void AddUsingOutParam(int x, int y, out int ans)
{
  ans = x + y;
}

int ans;
AddUsingOutParam(90, 90, out ans);

This can be useful for allowing the caller to obtain multiple outputs from a single method invocation. Tuples are another way to return multiple values out of a method call.

Discarding out Parameters


You can use a discard as a placeholder if you do now care about the value of an out parameter. Discards are temporary, dummy variables that are intentionally unused. They are unassigned, do not have a value, and might not even allocate any memory. This can provide a performance benefit and make the code more readable.

FillTheseValues(out int a, out _, out _);

The out Modifier in Constructors and Initializers


Parameters for constructors, field and property initializers, and query clauses can all be decorated with the out modifier.

Using the ref Modifier


Reference parameters are necessary when you want to allow a method to operate on (and usually change the values of) various data points declared in the caller's scope (such as a sorting or swapping routine).

public static void SwapStrings(ref string s1, ref string s2)
{
  string tempStr = s1;
  s1 = s2;
  s2 = tempStr;
}

Using the in Modifier


The in modifier passes a value by reference and prevents the called method from modifying the values. This may be used to reduce memory pressure.

Using the params Modifier


C# supports the use of parameter arrays using the params keyword. The params keyword allows you to pass into a method a variable number of identically typed parameters (or classes related by inheritance) as a single logical parameter. Arguments marked with the params keyword can also be processed if the caller sends in a strongly typed array or a comma-delimited list of items.

C# demands a method support only a single params argument which must be the final argument in the parameter list.

Defining Optional Parameters


Optional parameters cannot be listed before nonoptional parameters. Optional arguments involve specifying default arguments.

static void EnterLogData(string message, string owner = "Programmer")
{
  Console.WriteLine("Error: {0}", message);
  Console.WriteLine("Owner of Error: {0}", owner);
}

Using Named Arguments


Another language feature found in C# is support for named arguments. Named arguments allow you to invoke a method by specifying parameter values in any order you choose.

Understanding Method Overloading


C# allows a method to be overloaded. A method is overloaded when there are a number of identically named methods that differ by the number or type or parameters.

Checking Parameters for Null


If a method parameter is nullable and required by the method body, it is considered good programming practice to check that the parameter is not null before using it. If it is null, the method should throw an ArgumentNullException.

static void EnterLogData(string message, string owner = "Programmer")
{
  if (message == null)
  {
    throw new ArgumentNullException(message);
  }
  ...
}

A newer way (C# 10):

ArgumentNullException.ThrowIfNull(message);

Understanding the enum Type


An enum is a custom data type of name-value pairs. Do not confuse it with enumerator. An enumerator is a class or structure that implements the IEnumerable interface. Objects that support IEnumerable can work with the foreach loop.

// A custom enumeration
enum EmpTypeEnum
{
  Manager,
  Grunt,
  Contractor,
  VicePresident
}

By convention, the suffix of the enum type name is usually Enum. In the above, the first element is set to the value 0 and the rest follow an n+1 progression.

enum EmpTypeEnum
{
  Manager = 102,
  Grunt,
  Contractor,
  VicePresident
}

Controlling the Underlying Storage for an enum


By default, the storage type used to hold the values of an enumeration is System.Int32 (the C# int). You can change this:

enum EmpTypeEnum : byte
{
  Manager = 10,
  Grunt = 1,
  Contractor = 100,
  VicePresident = 9
}

Changing the underlying type can be useful when building a .NET Core app that will be deployed to a low-memory device.

Declaring enum Variables


EmpTypeEnum emp = EmpTypeEnum.Contractor;

Using the System.Enum Type


.NET Core enumerations get functionality from the System.Enum class type which defines several methods to interrogate and transform the enumeration. For example, the Enum.GetUnderlyingType() method takes a System.Type argument and in this case returns the data type used to store the values of the enumerated type.

Enum.GetUnderlyingType(emp.GetType()));

Dynamically Discovering an enum's Name-Value Pairs


Al C# enumerations support a method named ToString() which returns the string name of the enumeration's value.

Using Enums, Flags, and Bitwise Operations




Understanding the Structure


Structure types are well suited for modeling mathematical, geometrical, and other "atomic" entities in your application. Structures are types that can contain any number of data fields and members that operate on these fields. They can be thought of as a "lightweight class type" given that they provide a way to define a type that supports encapsulation but cannot be used to build a family of related types. They cannot be inherited and cannot be the base of a class.

struct Point
{
  public int X;
  public int Y;

  public void Increment()
  {
    X++; Y++;
  }
}

Note that in the above, it is typically considered bad style to define public data within a class or structure. You want to define private data that can be accessed and changed using public properties.

Creating Structure Variables


Point p2;
p2.X = 10;
p2.Y = 10;
p2.Display();

As an alternative, you can create structure variables using the C# new keyword which will invoke the structure's default constructor.

Structure Constructors


A structure can be designed with a custom constructor.

struct Point
{
  public int X;
  public int Y;

  public Point(int xPos, int yPos)
  {
    X = xPos;
    Y = yPos;
  }
  ...
}

Point p2 = new Point(50, 60);

With C# 10, you can also declare a parameterless (i.e. default) constuctor on a structure.

struct Point
{
  ...
  public Point()
  {
    X = 0;
    Y = 0;
  }
}

Using Field Initializers


New in C# 10, structure fields can be initialized when declared.

struct Point
{
  public int X = 5;
  public int Y = 7;
}

With this, the parameterless constructor would not need to initialize the X and Y fields.

Using Read-Only Structs


Structs can be marked as read-only if there is a need to make them immutable. Immutable objects must be set up at their initial construction, and they can be more performant because they cannot be changed.

readonly struct ReadOnlyPoint
{
...
}

Using Read-Only Members


The individual fields of a struct can be declared as readonly.

Using ref Structs


The ref modifier can be used when defining a struct to require all instances of the struct to be stack allocated and unable to be assigned as a property of another class. There are other limitations: they cannot be assigned to a variable of type object or dynamic and cannot be an interface type. They cannot implement interfaces. They cannot be used as a property of a non-ref struct. They cannot be used in async methods, iterators, lambda expressions, or local functions.

Using Disposable ref Structs


ref structs and read-only ref structs can be made disposable by adding a public void Dispose() method. This is needed since they cannot implement the IDisposable interface given they cannot implement interfaces.

Understanding Value Types and Reference Types


Unlike arrays, strings, and enumerations, C# structures do not have an identically named representation in the .NET Core library (there is not a System.Structure class). Structures are implicitly derived from System.ValueType.

The role of System.ValueType is to ensure that the derived type is allocated on the stack. Data allocated on the stack can be created and destroyed quickly as its lifetime is determined by the defining scope. Heap-allocated data is monitored by the .NET Core garbage collector and has a lifetime that is determined by many factors.

Functionally, the only purpose of System.ValueType is to override the virtual methods defined by System.Object to use value-based versus reference-based semantics.

Using Value Types, Reference Types, and the Assignment Operator


When you assign one value type to another, a member-by-member copy of the field data is achieved. When you apply the assignment operator to reference types, you are redirecting what the reference variable points to in memory. So if you have two references pointing to the same object on the managed heap, when the value is changed using one reference, the other reference reports the same changed value.

Using Value Types Containing Reference Types


When a value type contains other reference types, assignment results in a copy of the references. So you have two independent structures for example, each of which containing a reference to the same object in memory. To perform a deep copy, one approach is to implement the ICloneable interface.

Passing Reference Types by Value


If a reference type is passed into a method, it is really a copy of the reference getting passed in, and it is possible to therefore alter the object's state data.

Passing Reference Types by Reference


If you use the ref parameter modifier, you can pass a reference type by reference, which means not only can you change the state of the object, but you can also reassign the reference to a new object.

Final Details Regarding Value Types and Reference Types


Value Type
  • Allocated on the stack
  • Extends System.ValueType
  • Cannot be inherited from
  • Passed by value
  • Die when falling out of scope

Reference Type
  • Allocated on the managed heap
  • Can derive from any type except System.ValueType
  • Reference is passed by value
  • Dies when garbage collected

Understanding C# Nullable Types


Value types can never be assigned the value of null.

C# supports the concept of nullable data types. A nullable type can present all the values of its underlying type, plus null. Thus a nullable bool could be true, false, or null. This can be helpful when working with relational databases.

To define a nullable variable type, ? is suffixed to the underlying data type.

static void LocalNullableVariables()
{
  int? nullableInt = 10;
  double? nullableDouble = 3.14;
}

Using Nullable Value Types


The ? suffix is shorthand for creating an instance of the generic System.Nullable<T> structure type. System.Nullable<T> provides a set of members that all nullable types can make use of.

The ? is just shorthand for this:

Nullable<int> nullableInt = 10;

Using Nullable Reference Types


Nullable reference types use ? as well but it is not a shorthand for using System.Nullable<T> as only value types can be used in place of T.

Opting in for Nullable Reference Types


Support for nullable reference types is a significant feature added with C# 8. This was a big change and one of the reasons that C# 8 is only supported in .NET Core 3.0 and above.

Support for nullable reference types is controlled by setting a nullable context. This can be done for the entire project using the project file or just a file lines using compiler directives. With C# 10/.NET 6, nullable reference types are enabled by default.

Nullable Reference Types in Action


Warnings will be generated when trying to assign null to a non-nullable type in a nullable context. The nullable context allows the declarations of reference types to use the nullable annotation (?). Fine control of where the nullable contexts are in the project can be controlled using compiler directives.

Migration Considerations


Change Nullable Warnings to Errors


When you are ready to commit to nullable reference types, you can configure the nullable warnings as errors with the project file.

It is also possible to change the severity of any warning to an error.

Operating on Nullable Types


Several operators are provided for working with nullable types: the null-coalescing operator, the null-coalescing assignment operator, and the null conditional operator.

The Null-Coalescing Operator


A variable that might have a null value can make use of the ?? operator, which is the null-coalescing operator. This allows assigning a value to a nullable type if the retrieved value is null.

int myData = dr.GetIntFromDatabase() ?? 100;

This provides a more compact version of a traditional if/else condition.

The Null-Coalescing Assignment Operator


??= is the null-coalescing assignment operator. This operator assigns the left-hand side to the right-hand side only if the left-hand side is null.

int? nullableInt = null;
nullableInt ??= 12;
nullableInt ??= 14; // does not assign 14 to the variable since it is not null

The Null Conditional Operator


args?.Length

If args is null, the call to the Length property will not throw a runtime error.

Console.WriteLine($"You sent me {args?.Length ?? 0} arguments."); 

Understanding Tuples


A tuple is a light construct that can be used to retrieve more than one value from a method call, as an alternative to using the out method parameter.

Tuples are lightweight data structures that contain multiple fields. They were introduced in a limited way in C# 6, and as of C# 7, tuples use the new ValueTuple data type instead of reference types. This potentially saves a lot of memory. The ValueType type creates different structs based on the number of properties for a tuple. Each property in a tuple can also be assigned a specific name.

The two important considerations for tuples: the field are no validated and you cannot define your own methods. They really are intended to just be a lightweight data transport mechanism.

Getting Started with Tuples


To create a tuple, simply enclose the values to the tuple in parentheses. They do not need to be the same data type.

(string, int, string) values = ("a", 5' "c");

They are accessed by properties with names like ItemX.

Console.WriteLine($"First item: {values.Item1}");

Specific names can also be added to each property in the tuple on either the right or left side, but if you do both at the same time, the left side will be used only.

(string FirstLetter, int TheNumber, string SecondLetter) valuesWithNames = ("a", 5, "c");
var valuesWithNames2 = (FirstLetter: "a", TheNumber: 5, SecondLetter: "c")

Now the properties can be accessed with these names and the ItemX notation.

When setting the names on the right, the var keyword must be used to declare the variable. Setting the data types specifically causes the compiler to use the left side and ignore any custom names on the right.

Note also that the custom field names exist only at compile time and can not be inspected at runtime using reflection.

Also note: tuples can be nested inside other tuples.

var nt = (5, 4, ("a", "b"));

Using Inferred Variable Names


Understanding Tuple Equality/Inequality


The comparison operators will perform implicit conversions on data types within the tuples, including comparing nullable and non-nullable tuples and/or properties. Tuples that contain tuples can also be compared, if they have the same shape.

Understanding Tuples as Method Return Values


out parameters can be used to return more than one value from a method call. A class or structure could be created specifically to do this as well. But it's probably not worth doing so if it is going to be used as a data transport mechanism for only one method. Tuples are perfectly suited for this task.

Understanding Discards with Tuples


Understanding Tuple Pattern Matching switch Expressions


Deconstructing Tuples


Deconstructing is the term for separating out the properties of a tuple to be used individually.

(int x1, int y1) = myTuple;

Another use for this pattern is deconstructing custom types by having the individual properties of the type be returned by some method as a tuple. This method is conventionally named Deconstruct().

Deconstructing Tuples with Positional Pattern Matching


Summary


This chapter began with an examination of arrays. Then, we discussed the C# keywords that allow you to build custom methods. Recall that by default parameters are passed by value; however, you may pass a parameter by reference if you mark it with ref or out. You also learned about the role of optional or named parameters and how to define and invoke methods taking parameter arrays. After you investigated the topic of method overloading, the bulk of this chapter examined several details regarding how enumerations and structures are defined in C# and represented within the .NET Core base class libraries. Along the way, you examined several details regarding value types and reference types, including how they respond when passing them as parameters to methods and how to interact with nullable data types and variables that might be null (e.g., reference type variables and nullable value type variables) using the ?, ??, and ??= operators. The final section of the chapter investigated a long-anticipated feature in C#, tuples. After getting an understanding of what they are and how they work, you used them to return multiple values from methods as well as to deconstruct custom types. 
What is defined as a set of contiguous data points of the same type?
When an array is declared in C# and each index is not explicitly filled with a value, what is the value for the unset indexes?
What is the default value for a bool in C#?
What is an example of declaring an array in C# by specifying the total number of items in the array? (Declare an array of 3 ints)
What is an example of declaring an array using the C# array initialization syntax which specifies each array item? (Declare an array with three bools--each false)
What is an example of declaring an implicitly typed array in C#? (Declare an array with 1, 10, 100, and 1000)
What is the base class to every type in C#, including the fundamental data types?
What is the data type to declare an array with in C# if you want the subitems of the array to be any type?
What is the term for an array of multiple dimensions where each row is of the same length?
What is the term for an array of multiple dimensions where the inner arrays each may have a different length?
What is the property to return the number of items in an array in C#?
What is the static Array method in C# to reverse the contents of a one-dimensional array?
What is the difference between a method and function in C#?
What are methods within methods called in C#?
What in C# is a function declared inside another function that must be private and does not support overloading?
Do local functions support nesting in C#?
What does it mean for a parameter to be sent into a function by value?
What method can be called on a List<string> object in C# to convert it to an instance of string[] (an array of strings)?
Which of ? or : comes first in a ternary statement in C#?
What is the VS Code IDE recommended syntax for declaring an empty array of strings in C#?
What is the default way a parameter is sent into a function in C#?
In C#, what are the two cases that relate to exactly what is copied when a parameter is sent into a function by value?
What is an enumerator in C#?
By convention, the suffix of an enum type name in C# is usually what?
What is the parameter modifier in C# to mark a parameter as an output parameter?
What is the well-known special case of a reference type in C# that is still passed by value?
What is a term for a temporary, dummy variable that is intentionally unused?
What is the parameter modifier you can use in C# if you want a method to be able to change the value of a passed in argument?
What is the C# keyword that allows you to pass into a method a variable number of identically typed parameters as a single logical parameter?
What is a method called when there are multiple methods with the identical name but differ in the number or type of parameters?
What is the C# keyword for the custom data type of name-value pairs?
What is the C# interface that objects must support to work with the foreach loop (and objects that do can be called enumerators)?
What is the bitwise AND operator in C#?
What is the bitwise OR operator in C#?
What is the bitwise XOR operator in C#?
What is the ones' compliment operator in C# (that flips the bits)?
What did C# 6 introduce that can be used to shorten the syntax of defining single-line methods?
What is one line of code showing a method that adds two ints together and returns an int using the expression-bodied member feature of C#?
What is the left shift operator in C#?
What is the right shift operator in C#?
What does System.ValueType ensure about types derived from it in C#?
What is a nullable type in C#?
When does a value type variable die in C#?
What types in C# are allocated on the stack?
What C# type has the purpose of overriding the virtual methods defined by System.Object to use value-based instead of reference-based semantics?
What is the result of this (C#)? 0110 << 1
What is the result of this (C#)? 0110 >> 1
What is the result of this (C#)? 1100 & 0100
What is the result of this (C#)? 0110 | 0100
What is the result of this (C#)? 0110 ^ 0100
What is a one-line way to throw an ArgumentNullException if the variable message was null in C#?
What is the operator in C# to flip the bits of a binary number?
What is the result of this (C#)? 0011 ^ 1100
What is the result of this (C#)? 0111 ^ 1011
What is the ones' compliment of a binary number?
Why can you not reassign a reference type argument to be a new object inside a method call in C#?
If you want to reassign a reference to point to a new object inside a method call in C#, what parameter modifier must you use?
What types in C# are allocated on the managed heap?
A reference type in C# can inherit from any type except for what?
When does a reference type variable die in C#?
What values can a nullable bool have in C#?
When using the ? suffix to use a nullable value type, this is really just shorthand for what type?
With the System.Nullable<T> structure type, what kind of types can be used as T?
What is an example of declaring a variable of a nullable int type in C#?
What is the null-coalescing operator in C# (for the benefit of a more compact version of a traditional if/else condition)?
What is the null-coalescing assignment operator in C# (assigns the left-hand side to the right-hand side only if the left-hand side is null)?
What is an example using the null conditional operator in C# (Length property of args but do not throw an error if args is null)?
What light construct in C# provides a convenient way to return more than one value from a method?
When a type in C# returns a tuple from a method in order to return out the class instance's individual properties, what is the method conventionally called?
What does C# support for the purpose of creating a set of symbolic names that map to known numerical values?
What does it look like to declare an enum EmpTypeEnum that uses byte as the storage value rather than an int in C#?
What class type do .NET Core enumerations get functionality from?
What is the process of changing the implementation of a virtual (or abstract) method of a base class in a derived class in C# called?
The <Nullable> node in a C# project file listing can be used to opt in or configure what?
With C# 10, are nullable reference types enabled or disabled by default?
How to declare a tuple called values in C# that has a string "a", an int 5, and a string "c" using the var keyword?
What type is this (C#)? var values = ("a", 5, "c");
What type of method parameters in C# must be assigned by the method being called (a compiler error occurs if the called method fails to assign it)?
Pro C# 10 with .NET 6 Chapter 5. Understanding Encapsulation Study cards

Introducing the C# Class Type


A class is a user-defined type composed of field data (member variables) and members that operate on this data. Collectively, the set of field data represents the "state" of a class instance. A class instance is otherwise known as an object. The power of object-oriented languages is grouping data and related functionality in unified class definition allows you to model your software after entities in the real world.

A class in C# is defined using the class keyword. After defining the class, you need to consider the set of member variables that will be used to represent its state. Note that field data of a class should seldom (if ever) be defined as public. It is far better design to define data as private and allow controlled access to the data via properties.

class Car
{
  public string petName;
  public int currSpeed;
}

Next is the set of member variables that model its behavior.

class Car
{
  public void PrintState()
    => Console.WriteLine("{0} is going {1} MPH.", petName, currSpeed);

  public void SpeedUp(int delta)
    => currSpeed += delta;
}

Allocating Objects with the new Keyword


Objects must be allocated into memory using the new keyword.

Understanding Constructors


Programmers typically want to assign relevant values to the object's field data before use. It is not uncommon for a class to have dozens of fields of data to contend with.

C# supports the use of constructors, which allow the state of an object to be established at the time of creation. A constructor is a special method of a class that is called indirectly when creating an object using the new keyword. Constructors will never have a return value (not even void) and are always named identically to the class that they are constructing.

Understanding the Role of the Default Constructor


Every C# class is provided with a default constructor that you can redefine. By definition, a default constructor never takes arguments. If you are not satisfied with the default constructor, here is an example of how to update the class:

class Car
{
  public string petName;
  public int currSpeed;
  
  public Car()
  {
    petName = "Chuck";
    currSpeed = 10;
  }
...
}

Defining Custom Constructors


What makes one constructor different from another in the eyes of the C# compiler is the number and/or type of the constructor arguments. When methods are defined with the same name but differ in the number or type of arguments, the methods have been overloaded. Overloading the constructor provides a way to have more than one constructor.

Constructors As Expression-Bodied Members


C# 7 added additional uses for the expression-bodied member style. Constructors, finalizers, and get/set accessors on properties and indexers now accept the new syntax.

public Car(String pn) => petName = pn;

Constructors with out Parameters


Constructors can use out parameters.

public Car(string pn, int cs, out bool inDanger)
{
  petName = pn;
  currSpeed = cs;
  if (cs > 100)
  {
    inDanger = true;
  }
  else
  {
    inDanger = false;
  }
}

Understanding the Default Constructor Revisited


All class are provided with a free default constructor. As soon as you define a custom constructor with any number of parameters, the default constructor is silently removed from the class and is no longer available. Therefore if you want to have a different constructor as well as a default constructor, you must define the default.

Understanding the Role of the this Keyword


The this keyword provides access to the current class instance. This can be used to resolve scope ambiguity, for example when an incoming parameter is named identically to a data field of the class.

A common naming convention is to start private class-level variable names with an underscore ( e.g. _driverName).

Chaining Constructor Calls Using this


Another use of the this keyword is to design a class using a technique termed constructor chaining. This design pattern is helpful when you have a class that defines multiple constructors.

Observing Constructor Flow


Revisiting Optional Arguments


Understanding the static Keyword


A C# class may define any number of static members which are declared using the static keyword. These members must be invoked from the class, rather than from an object. Static members are items that are deemed (by the class designer) to be so commonplace that there is no need to create an instance of the class before invoking the member. They are quite commonly found in utility classes. By definition, a utility class is a class that does not maintain any object-level state and is never created with the new keyword. It only exposes functionality with static members. Console, Math, Environment, and GC are a few of the utility classes in the .NET Core base class libraries.

Defining Static Field Data


Defining Static Methods


Defining Static Constructors


Defining Static Classes


Importing Static Members via the C# using Keyword


Defining the Pillars of OOP


All object-oriented languages contend with the three core principles which are called the pillars of object-oriented programming: encapsulation, inheritance, and polymorphism.

Understanding the Role of Encapsulation


Encapsulation boils down to the language's ability to hide unnecessary implementation details from the user. Closely related is the idea of data protection. Ideally, an object's state data should be specified using the private, internal, or protected keywords.

Understanding the Role of Inheritance


Inheritance boils down to the language's ability to allow you to build new class definitions based on existing class definitions. System.Object is always the topmost parent in any class hierarchy in .NET.

Understanding the Role of Polymorphism


Polymorphism is a language's ability to treat related objects in a similar manner. A base class can define a set of members (formally termed the polymorphic interface) that are available to all descendants. A class's polymorphic interface is constructed using any number of virtual or abstract members.

A virtual member is a member in a base class that defines a default implementation that may be changed (or more formally speaking, overridden) by a derived class. In contrast, an abstract method is a member in a base class that does not provide a default implementation but does provide a signature. An abstract method must be overridden by a derived type.

Understanding C# Access Modifiers


Types (classes, interfaces, structures, enumerations, and delegates) and their members (properties, methods, constructors, and fields) are defined using a keyword that specifies how visible that item is to other parts of the application.



Using the Default Access Modifiers


By default, type members are implicitly private, while types are implicitly internal.

class Radio
{
  Radio(){}
}

In the above example, the class is implicitly internal and the constructor is implicitly private.

The public keyword must be used to allow other parts of the program to invoke members of an object.

Using Access Modifiers and Nested Types


A nested type is a type declared directly within the scope of a class or structure.

Understanding the First Pillar: C#'s Encapsulation Services


Public fields (except for public constants and public read-only fields) typically have no place in a production-level class definition. Members of a class that represent an object's state should not be marked as public.

Encapsulation provides a way to preserve the integrity of an object's state data. You should get in the habit of defining private data which is indirectly manipulated either through a pair of public accessor (get) and mutator (set) methods or a public property.

A well-encapsulated class should protect its data and hide the details of how it operates from the outside world. This can be called black-box programming. This also provides the benefit of allowing the object to change how a given method is implemented without breaking any existing code making use of it.

Encapsulation Using Traditional Accessors and Mutators


A traditional approach to allow interacting with certain private fields of a class is to define an accessor (get method) and a mutator (set method).

Encapsulation using Properties


.NET Core languages prefer to use properties for this. Properties are just a container for "real" accessor and mutator methods, named get and set, respectively.

class Employee
{
  // Field data
  private string _empName;
  private int _empId;
  private float _currPay;
  // Properties
  public string Name
  {
    get { return _empName; }
    set {
      if (value.Length > 15)
      {
        Console.WriteLine("Error");
      }
      else
      {
        _empName = value;
      }
    }
  }
  public int Id
  {
    get { return _empId; }
    set { _empId = value; }
  }
}

A C# property is defined by a get scope and a set scope directly within the property itself. Note how properties do not make use of parentheses (like a method would) when being defined.

Within the set scope of a property, you use a token named value which represents the incoming value used to assign the property by the caller. It is not a true C# keyword, rather it is what is called a contextual keyword.

public string Name
{
  get { return _empName; }
  set {
    if (value.Length > 15)
    {  Console.WriteLine("error");
    }
    else
    {
      empName = value;
    }
  }
}

Properties (as opposed to accessor and mutator methods) make your types easier to manipulate in that properties are able to respond to the intrinsic operators of C#. For example, you can use the ++ operator on a property.

Properties As Expression-Bodied Members


Property get and set accessors can also be written as expression-bodied members.

public int Age
{
  get => empAge;
  set => empAge = value;
}

Using Properties Within a Class Definition


Properties (specifically the set portion) are common places to package up the business rules of your class. Suppose you had some check in the constructor and also the property: that is duplicated code. To isolate all of the checking to one location, you can always use the properties in the constructor and anywhere in the class. You might always use properties within your class whenever you need to get or set the values. This ensures that the business rules are always enforced.

Read-Only Properties


You can configure a property to be read-only by omitting the set block. Properties that only have a getter can also be simplified using expression body members. The following two snippets are equivalent:

public string SocialSecurityNumber
{
  get { return _empSSN; }
}

public string SocialSecurityNumber => _empSSN;

Write-Only Properties


Omit the get block.

Mixing Private and Public Get/Set Methods on Properties


public string SocialSecurityNumber
{
  get => _empSSN;
  private set => _empSSN = value;
}

Revisiting the static Keyword: Defining Static Properties


class SavingsAccount
{
  public static double InterestRate
  {
    get { return _currInterestRate; }
    set { _currInterestRate = value; }
  }
...
}

Pattern Matching with Property Patterns


Extended Property Patterns


Understanding Automatic Properties


It can get rather verbose when you have a lot of the same simple property definitions. To streamline the process of providing simple encapsulation of field data, you can use automatic property syntax.

class Car
  // Automatic properties! No need to define backing fields.
  public string PetName { get; set; }
  public int Speed { get; set; }
  public string Color { get; set; }
}

Visual Studio and VS Code both provide the prop code snippet. Type prop inside a class definition and Tab twice to generate starter code for a new automatic property.

Note that the only way to see the name of the autogenerated private backing field is by making use of a tool such as ildasm.exe.

It is possible to define a "read-only automatic property" by omitting the set scope. It is not possible to define a write-only automatic property.

Interacting with Automatic Properties


A class defining automatic properties will always need to use property syntax to get and set the underlying values.

Automatic Properties and Default Values


Automatic properties that encapsulate numerical or Boolean data will have hidden backing fields automatically assigned a safe default value like 0 for numerical data and false for Booleans. If you use automatic property syntax to wrap another class variable, the hidden private reference type will also be set to a default value of null which can be problematic if you are not careful.

Initializing Automatic Properties


Recall that a data field of a class can be directly assigned an initial value upon declaration:

class Car
{
  private int numberOfDoors = 2;
}

In a similar manner, C# allows you to assign an initial value to the underlying backing field generated by the compiler.

class Garage
  // The hidden backing field is set to 1
  public int NumberOfCars { get; set; } = 1;

  // The hidden backing field is set to a new Car object.
  public Car MyAuto { get; set; } = new Car();

  public Garage(){}
  public Garage(Car car, int number)
  {
    MyAuto = car;
    NumberOfCars = number;
  }
}

Understanding Object Initialization


A constructor allows you to specify startup values when creating a new object. Related to that, properties allow you to get and set underlying data in a safe manner. When using code from a library, it is common for there not to be a specific constructor to set every underlying state data you need to. So typically you will choose the best constructor possible and then make assignments using a handful of provided properties.

Looking at the Object Initialization Syntax


C# offers object initializer syntax to help streamline the process of getting an object up and running. It is possible to create a new object variable and assign a slew of properties and/or public fields in a few lines of code using this syntax. Syntactically, the object initializer consists of a comma-delimited list of specified values enclosed by the { and } tokens. Each member in the initialization list maps to the name of a public field or public property in the object being initialized.

// Make a Point by setting each property manually.
Point firstPoint = new Point();
firstPoint.X = 10;
firstPoint.Y = 10;

// Or make a Point via a custom constructor
Point anotherPoint = new Point(20, 20);

// Or make a Point using object init syntax
Point finalPoint = new Point { X = 30, Y = 30 };

Behind the scenes when using the object initialization syntax, the type's default constructor is invoked, followed by setting the values to the specified properties. Therefore the object initialization syntax is just a shorthand notation for the syntax used to create a class variable using a default constructor and to set the state data property by property.

It is important to remember that the object initialization process is using the property setter implicitly. If the property setter is marked private, this syntax cannot be used.

Using init-Only Setters


A new feature in C# 9.0 is init-only setters. These setters enable a property to have its value set during initialization, but after construction is complete, the property becomes read-only. These types of properties are called immutable.

class PointReadOnlyAfterCreation
{
  public int X { get; init; }
  public int Y { get; init; }
}

Calling Custom Constructors with Initialization Syntax


Be aware that when you are constructing a type using object initialization syntax, you are able to invoke any constructor defined by the class.

Point pt = new Point(10, 16) { X = 100, Y = 100 };

Initializing Data with Initialization Syntax


Rectangle myRect = new Rectangle
{
  TopLeft = new Point { X = 10, Y = 10},
  BottomRight = new Point { X = 200, Y = 200}
};

Working with Constant and Read-Only Field Data


Sometimes you want an immutable property (a property that you do not want changed at all, either from the time it was compiled or after it was set during construction).

Understanding Constant Field Data


C# offers the const keyword to define constant data, which can never change after the initial assignment. Constant fields of a class are implicitly static.

class MyMathClass
{
  public const double PI = 3.14;
}

The thing to always remember is that the initial value assigned to the constant must be specified at the time you define the constant. Trying to assign the value of the PI above in the constructor would throw an error because the constructor is invoked at runtime, and the value of constant data must be known at compile time.

Constant Interpolated Strings


Introduced in C# 10, const string values can use string interpolation in their assignment statements as long as all of the components that are used are also const strings. 

Understanding Read-Only Fields


Closely related to constant data is read-only field data, which should not be confused with read-only properties. A read-only field cannot be changed after the initial assignment or you will receive a compile-time error. Unlike a constant, the value assigned to a read-only field can be determined at runtime. Therefore it can be legally assigned within the scope of a constructor but nowhere else.

This can be helpful when reading an external file to obtain a value but you need to ensure the value will not change after that point.

class MyMathClass
{
  // Read-only fields can be assigned in constructors,
  // but nowhere else.
  public readonly double PI;

  public MyMathClass ()
  {
    PI = 3.14;
  }
}

Understanding Static Read-Only Fields


Unlike a constant field, a read-only field is not implicitly static. If you want to expose the read-only field from the class level, you must explicitly use the static keyword.

Understanding Partial Classes


The partial keyword allows for a single class to be partitioned across multiple code files. When you scaffold Entity Framework Core classes from a database, the created classes are all created as partial classes. This may represent an intermediate stage toward refactoring a class that has grown over time into something difficult to manage.

Each part of the partial class must be marked with the partial keyword. Partial classes make no difference after compilation; the whole idea is realized only during design time. The only requirement when defining partial types is that the type's name is identical and defined within the same .NET Core namespace.

Recall that any methods in top-level statements must be a local function. The top-level statements are implicitly defined in a partial Program class, allowing for the creation of another partial Program class to hold regular methods.

Records




What are a special reference type in C# that provide methods for equality using value semantics and data encapsulation?
What is a user-defined type composed of field data (member variables) and members that operate on this data (C# terminology)?
In the eyes of the C# compiler, what makes the different constructors of a class different?
What is an instance of a class otherwise known as (C#)?
The power of object-oriented languages allowing you to group data and related functionality in unified class definitions is that it allows you to do what?
What keyword in C# provides access to the current class instance?
What methods in C# allow the state of an object to be established at the time of creation?
public Car(string pn) => petName = pn; This C# constructor is an example of what type of member?
What is the "freebie" that every C# class is provided, which never takes arguments, but allows all field data of the class to be set to an appropriate default value, and you can redefine it if you want?
How can you redefine the default constructor of a C# class?
Record types in C# are really one specialized type of what?
C# supports mutable record types by using standard (not init-only) setters, but record types are really intended to be used for data models that are what?
How is a constructor named in C#?
What is a special method of a class that is called indirectly when creating an object using the new keyword in C#?
What is the keyword used to define a class in C#?
What is the keyword in C# to allocate an object into memory?
What are supported by C# and allow the state of an object to be established at the time the object is created?
What is a special method of a class that is called indirectly when creating an object using the new keyword (C#)?
What kind of members must be invoked from the class in C# (rather than an object)?
Members of a class deemed to be so commonplace that there is no need to create an instance of a class will be declared as what kind of members (C#)?
What kind of class is a class that does not maintain any object-level state and is never created with the new keyword?
What kind of members does a C# utility class expose functionality with?
What are the three pillars of OOP that all object-oriented programming languages must content with?
What pillar of OOP boils down to the language's ability to hide implementation details from the user?
What pillar of OOP boils down to the language's ability to allow you to build new class definitions based on existing class definitions?
What is the topmost parent class in any and every class hierarchy in .NET?
What pillar of OOP boils down to the language's ability to treat related objects in a similar way?
What type of member in a C# base class defines a default implementation that may be overriden by a base class?
What type of member in a C# base class provides only a signature and must be overridden by a derived type?
In C#, properties, methods, constructors, and fields are all considered what?
What is the default applied access modifier for a type in C#?
What is the default applied access modifier for a type member in C#?
What is a type called when it is declared directly within the scope of a class or structure in C#?
The traditional approach to allow interacting with certain private fields of a class is to define 2 methods called what?
What is the language feature preferred to use for encapsulation over accessor and mutator methods in .NET Core languages?
What type members in C# are just a container for "real" accessor and mutator methods, named get and set?
What is the token, or contextual keyword (not a true C# keyword), that can be used within the set scope of a property to represent the incoming value used to assign the property by the caller?
How do you make a property read-only in C#?
How do you make a property write-only in C#?
What C# feature can be used to streamline a lot of repetitive, basic properties?
What can you type in both Visual Studio and Visual Studio Code (and hit tab twice) to generate starter code for a new automatic property?
What is the shorthand notation offered by C# used to create a class variable using a constructor and then set the state data by property?
Can the object initialization syntax in C# be used to set a property where the property setter is marked private?
What keyword does C# offer to define constant data, which can never change after the initial assignment, and the value of which must be known at compile time?
Can a constant in C# have its value determined at runtime?
Why can the value of a constant in C# not be assigned inside a constructor?
What is the condition for a const string value to use string interpolation in their assignment statement (new in C# 10)?
How is a read-only field different from a constant in C#?
What is the keyword in C# that allows a single class to be partitioned across multiple code files?
When defining a class in C# across multiple files, each part must be marked with what keyword?
What is the special reference type that provides synthesized methods for equality using value semantics and data encapsulation in C#?
What is the following equivalent to (C#)? record CarRecord
Defining a record like this in C# removes the need for what property? record CarRecord(string Color);
What method do record types using positional parameters have (a method with an out parameter for each positional parameter in the declaration)?
How do record types in C# behave with Equals(), ==, and !=?
What is the construct in C# that can be used to create a true copy of a record with one or more properties modified?
What are the value type equivalent of record types (new in C# 10)?
Pro C# 10 with .NET 6 Chapter 6. Understanding Inheritance and Polymorphism Study cards

Understanding the Basic Mechanics of Inheritance


Inheritance is an aspect of OOP that facilitates code reuse. Code reuse comes in two forms: inheritance and the containment/delegation model. Inheritance can be described as an "is-a" relationship and the containment/delegation model can be described as a "has-a" relationship.

Specifying the Parent Class of an Existing Class


Classical inheritance allows you to build new class definitions that extend the functionality of an existing class. The existing class that serves as the basis for new classes is termed the base class, superclass, or parent class. The extending classes are termed derived or child classes. In C#, the colon operator is used to establish the "is-a" relationship.

class MiniVan : Car
{
}

Although constructors are typically defined as public, a derived class never inherits the constructors of a parent class. Constructors are used to construct only the class that they are defined within. They can be called by a derived class through constructor chaining.

Always remember that inheritance preserves encapsulation. Private members can be accessed only by the class that defines it.

Regarding Multiple Base Classes


C# demands that a given class have exactly one direct base class. Multiple inheritance is not supported in C#. It is supported in unmanaged C++.

Using the sealed Keyword


The sealed keyword prevents inheritance from occurring. When a class is marked as sealed, the compiler will not allow classes to derive from it. Sealing a class often makes sense when you are designing a utility class. C# structures are always implicitly sealed. Therefore a structure or class cannot be derived from a structure. A structure also cannot be derived from a class.

Revisiting Visual Studio Class Diagrams


Understanding the Second Pillar of OOP: The Details of Inheritance


Calling Base Class Constructors with the base Keyword


The default constructor of a base class is called automatically before the logic of the derived constructor is executed. It is a good idea to implement the subclass constructors to explicitly call an appropriate custom base class constructor.

public Manager(string fullName, int age, int empId, float currPay, string ssn, int numbOfOpts)
  : base(fullName, age, empId, currPay, ssn, EmployeePayTypeEnum.Salaried)
{
  // This property is defined by the Manager class.
  StockOptions = numbOfOpts;
}

This indicates a derived constructor is passing data to the immediate parent constructor.

The base keyword can be used whenever a subclass wants to access a public or protected member defined by a parent class. Use of this keyword is not limited to constructor logic.

Recall that once you add a custom constructor to a class definition, the default constructor is silently removed.

Keeping Family Secrets: The protected Keyword


Public items are directly accessible from anywhere, while private items can be accessed only by the class that has defined them. C# like many other languages provides an additional keyword, protected.

Protected members can be accessed directly by any descendent. Convention is that protected members are named PascalCased and not underscore-camelCase.

The benefit of defining protected members is that derived types no longer have to access the data indirectly through the public interface, which is also a potential downside as business rules could you bypassed. Protected members involve a level of trust between the parent and child classes. Outside the family, protected data is regarded as private.

Adding a sealed Class


A sealed class cannot be extended by other classes. You might find, when building a class hierarchy, that a certain branch in the inheritance chain should be "capped off."

Understanding Inheritance with Record Types


The new C# 9.0 record types support inheritance.

Inheritance for Record Types with Standard Properties


Inheritance for Record Types with Positional Parameters


Nondestructive Mutation with Inherited Record Types


Equality with Inherited Record Types


Deconstructor Behavior with Inherited Record Types


Programming for Containment/Delegation


The "has-a" relationship is known as containment/delegation or aggregation.

Delegation is simply the act of adding public members to the containing class that use the contained object's functionality.

partial class Employee
{
  // Contain a BenefitPackage object.
  protected BenefitPackage EmpBenefits = new BenefitPackage();
  
  // Expose certain benefit behaviors of object.
  public double GetBenefitCost() => EmpBenefits.ComputePayDeduction();

  // Expose object through a custom property
  public BenefitPackage Benefits
  {
    get { return EmpBenefits; }
    set { EmpBenefits = value; }
  }
}

Understanding Nested Type Definitions


In C# it is possible to define a type directly within the scope of a class or structure. The nested (or inner) type is considered a member of the nesting (or outer) class and in the eyes of the runtime can be manipulated like any other member.

public class OuterClass
{
  // A public nested type can be used by anybody.
  public class PublicInnerClass {}
  
  // A private nested type can only be used by members
  // of the containing class
  private class PrivateInnerClass {}
}

Nested types allow you to gain complete control over the access level of the inner type because they may be declared privately. Recall that non-nested classes cannot be declared using the private keyword. Because a nested type is a member of the containing class, it can access private members of the containing class. Often a nested type is useful as a helper for the outer class and is not intended to be used by the outside world.

Understanding the Third Pillar of OOP: C#'s Polymorphic Support


Using the virtual and override Keywords


Polymorphism provides for a way for a subclass to define its own version of a method defined by its base class, using the process termed method overriding. If a base class wants to define a method that may be, but does not have to be, overridden by a subclass, it must mark the method with the virtual keyword. Methods that have been marked with the virtual keyword are called virtual methods.

When a subclass wants to change the implementation details of a virtual method, it does so by using the override keyword, and the default behavior can be used using the base keyword.

public override void GiveBonus(float amount)
{
...
  public override void GiveBonus(float amount)
  {
    base.GiveBonus(amount);
    Random r = new Random();
    StockOptions += r.Next(500);
  }
}

Overriding Virtual Members with Visual Studio/Visual Studio Code


If you type the word override within the scope of a class type and then hit the spacebar, IntelliSense will display a list of all the overridable members defined in the parent classes and excluding methods that are already overridden.

Sealing Virtual Members


You can use the sealed keyword to seal certain methods in a class that is not sealed.

Understanding Abstract Classes


If you have a class that is meant to be used as a parent class but not actually have class instances, you should enforce that instances of it cannot be created by using the abstract keyword. This creates an abstract base class.

Understanding the Polymorphic Interface


When a class has been defined as an abstract base class via the abstract keyword, it may define any number of abstract members. Abstract members can be used whenever you want to define a member that does not supply a default implementation but must be accounted for by each derived class. This enforces a polymorphic interface on each descendent.

An abstract base class's polymorphic interface refers to its set of virtual and abstract methods. 

Understanding Member Shadowing


C# provides a facility that is the logical opposite of method overriding, termed shadowing. Formally, if a derived class defines a member that is identical to a member defined in a base class, the derived class has shadowed the parent's version. In the real world, the possibility of this occurring is greatest when subclassing a class that you did not create yourself, such as from a third-party package.

This can be default with by using the override keyword if the parent class method is abstract. If it isn't and you do not have access to change it, you can use the new keyword.

Understanding Base Class/Derived Class Casting Rules


A class instance can be stored in a variable of a type where the type is the parent type of the object's class. It is always safe to store a derived object within a base class reference. This is called an implicit cast.

The compiler will not allow storing a derived class as a System.Object variable though because object is higher up the inheritance chain than the parent class. The compiler will not allow an implicit cast in order to keep the code as type-safe as possible. If you know that the object is compatible, you can perform an explicit cast with the casting operator.

Using the C# as Keyword


Explicit casting is evaluated at runtime. Therefore the compiler can allow explicit casts that will result in runtime exceptions. C# provides the as keyword to quickly determine at runtime whether a given type is compatible with another. When you use the as keyword, you are able to determine compatibility by checking against a null return value:

foreach (object item in things)
{
  Hexagon h = item as Hexagon;
  if (h == null)
  {
    Console.WriteLine("Item is not a hexagon.");
  }
  else
  {
    h.Draw();
  }
}

Using the C# is Keyword


The is keyword can be used to determine whether two items are compatible. is will return false, rather than null, if the types are incompatible.



static void GivePromotion(Employee emp)
{
  Console.WriteLine("{0} was promoted.", emp.Name);
  if (emp is SalesPerson)
  {
    Console.WriteLine("{0} made {1} sales.", emp.Name, ((SalesPerson)emp).SalesNumber);
  }
  else if (emp is Manager)
  {
    ...
  }
}

Here you are performing a runtime check to determine what the incoming base class reference is actually pointing to in memory. The is keyword can also assign the converted type to a variable if the cast works. This cleans up the preceding method by preventing the "double-cast" problem.

static void GivePromotion(Employee emp)
{
  Console.WriteLine("{0} was promoted!", emp.Name);
  // Check if is SalesPerson, assign to variable s
  if (emp is SalesPerson s)
  {
    Console.WriteLine("{0} made {1} sale(s)., s.Name, s.SalesNumber);
  }
...
}

C# 9.0 introduced additional pattern matching capabilities:

if (emp is not Manager and not SalesPerson)
{
  ...
}

Discards with the is Keyword


The is keyword can be used with the discard variable placeholder. To create a catchall in your if or switch statement:

if (obj is var _)
{
  // do something
}

This will match everything, so be careful about the order in which you use the comparer with the discard.

Revisiting Pattern Matching


static void GivePromotion(Employee emp)
{
  switch (emp)
  {
    case SalesPerson s:
      Console.WriteLine(...);
      break;
    case Manager m:
      ...
   }
}

Discards with switch Statements


Discards can also be used in switch statements:

case Employee _:
  ...
  break;

Understanding the Super Parent Class: System.Object


You may have noticed that the base classes in the example hierarchies do not explicitly specify their parent classes. In .NET, every type ultimately derives from a base class named System.Object, represented in C# with the object keyword. System.Object defines a set of common members for every type in the framework. When you build a class that does not explicitly define its parent, the compiler automatically derives your type from System.Object.

The System.Object defines a set of methods, some marked virtual, and others marked static.



Overriding System.Object.ToString()


public override string ToString() => $"[First Name: {FirstName}; Last Name: {LastName};
Age: {Age}]";

Remember that you may also need to account for data up the chain of inheritance. To do so, obtain the ToString() value from the parent using the base keyword, and then append the derived class's custom information.

Overriding System.Object.Equals()


By default, Equals() returns true if two objects being compared reference the same object instance in memory. It could be useful to re-implement this method to instead compare if state were the same between objects.

Overriding System.Object.GetHashCode()


When a class overrides the Equals() method, it should also override the default GetHashCode(). A hash code is a numerical value that represents an object as a particular state. If you create two strings with the same value, they will have the same hash code.

By default, the System.Object.GetHashCode() uses the object's current location in memory to yield the hash value. If you are building a custom type that you intend to store in a Hashtable type (within the System.Collections namespace), you should override this member. Internally, the Hashtable will be invoking Equals() and GetHashCode() to retrieve the correct object. More specifically, the System.Collections.Hashtable class calls GetHashCode() internally to gain a general idea of where the object is located, and then calls Equals() to determine the exact match.

If you can identify a piece of data that should be unique for all instances and immutable, you can override GetHashCode() by having it call the default GetHashCode() on that unique data value.

Using the Static Members of System.Object


System.Object defines two static members that test for value-based or reference-based equality: Equals() and ReferenceEquals().

Summary


This chapter explored the role and details of inheritance and polymorphism. Over these pages you were introduced to numerous new keywords and tokens to support each of these techniques. For example, recall that the colon token is used to establish the parent class of a given type. Parent types are able to define any number of virtual and/or abstract members to establish a polymorphic interface. Derived types override such members using the override keyword. 
In addition to building numerous class hierarchies, this chapter also examined how to explicitly cast between base and derived types and wrapped up by diving into the details of the cosmic parent class in the .NET base class libraries: System.Object. 
According to the Pro C# book, what are the two forms of code reuse?
Inheritance can be described as what kind of relationship?
Containment/delegation can be described as what kind of relationship?
In .NET, is it safe to store an object of a derived class type within a base class reference?
What type of cast is it called in .NET when a derived class object is stored within a base class reference?
What type of casting in .NET is why you can pass an object argument as a method parameter where the parameter is a parent class of the object's class?
Is it possible in .NET to cast an object from a base class type to a derived type that is lower in the inheritance chain?
Hexagon h = item as Hexagon What value will h have if item is not a type that can be explicitly cast to a Hexagon?
What instance method of System.Object compares items and, by default, only returns true if the items being compared refer to the same item in memory?
If you override the System.Object Equals() method in C#, then what other method should you also override (because both of these methods are used internally by Hashtable types to retrieve subobjects from the container)?
When you build a class in C# that does not explicitly define its parent class, what is the parent class?
What method of System.Object does ValueType override so that structures can do value-based comparisons?
"For the time being, you can understand this method (when overridden) is called to free any allocated resources before the object is destroyed." What method of System.Object does this quote describe?
What method of System.Object returns an int that identifies a specific object instance?
What method of System.Object returns a string representation of the object using the fully qualified name (<namespace>.<type name>)?
What keyword in C# is similar to as but it returns false instead of null when an explicit cast is not possible?
What method of System.Object returns a Type object that fully describes the object you are currently referencing (this is a runtime type identification method available to all objects)?
What method of System.Object exists to return a member-by-member copy of the current object, which is often used when cloning an object?
What keyword does C# provides to quickly determine at runtime whether a given type is compatible with another (by checking against a null return value)?
What two keywords can you use in C# to trap the possibility of an invalid explicit cast resulting in a runtime exception?
When is explicit casting evaluated in .NET (at compile time or runtime)?
What type of cast can you use in .NET when you know the object reference is pointing to a compatible class in memory but the compiler cannot?
What is the ultimate base class in the .NET system?
What are three terms for the existing class that serves as the basis for new classes in classical inheritance?
What are two terms for the extending classes in classical inheritance?
What is the operator that establishes an "is-a" relationship (inheritance) in C#?
Does a derived class inherit the constructor of a parent class in C#?
What can be used/what is it called in C# to allow a constructor to be called by a derived class?
Does C# support multiple inheritance?
What is it called when a class in a programming language can have more than one direct parent class?
What is the keyword in C# that prevents inheritance from occurring?
What category of types in C# is always sealed?
What C# keyword can be used whenever a subclass wants to access (not override) a public or protected member defined by a parent class?
What happens to the default constructor in a C# class when a custom constructor is added to the class definition?
What kind of C# members are directly accessible by any descendent of the class but outside the family, regarded as private?
What C# keyword can be used to specify that a class cannot be extended by other classes?
What is the act of adding public members to a class containing an object that use the contained object's functionality?
Can non-nested classes be declared using the private keyword in C#?
What C# keyword is used on a method that may be, but does not have to be, overridden by a subclass?
What keyword does a child class in C# use when it wants to change the implementation details of a virtual method?
What keyword can be used to enforce that a parent class cannot have instances of it created in C#?
What keyword should be used in C# to define a method that does not provide a default implementation and must be accounted for in each derived class?
An abstract base class's polymorphic interface in C# refers to its what?
If you were using a third-party package, and your subclass of a class from the package defined an identical member as the parent class, this is an example of what happening?
Pro C# 10 with .NET 6 Chapter 7. Understanding Structured Exception Handling Study cards

Ode to Errors, Bugs, and Exceptions


The Role of .NET Exception Handling


The .NET platform provides a standard technique to send and trap runtime errors that is common to all languages targeting the .NET platform: structured exception handling.

The Building Blocks of .NET Exception Handling


The four interrelated entities involve in structured exception handling: a class type that represents details of the exception. A member that throws an instance of the exception class to the caller under the correct circumstances. A block of code on the caller's side that invokes the exception-prone member. A block of code on the caller's side that will process (or catch) the exception, should it occur.

C# has five keywords to throw and handle exceptions: try, catch, throw, finally, when.

The object that represents the problem at hand is a class extending System.Extension (or a descendent thereof).

The System.Exception Base Class


All exceptions ultimately derive from System.Exception.

What is the standard technique provided by the .NET platform to send and trap errors, that is common to all languages targeting the platform, called?
All exceptions in C# ultimately derive from what class?
What read-only property of System.Exception retrieves a collection of key-value pairs (represented by an object implementing IDictionary) that provide additional, programmer-defined information about the exception?
What read-only property of System.Exception can be used to obtain information about previous exceptions that caused the current exception to occur?
When you throw a new System.Exception object in .NET, what read-only property gets set via the class constructor?
What read-only property of System.Exception contains a string that identifies the sequence of calls that triggered the exception?
What is the keyword used in C# to raise an exception?
What can you make use of in C# programming when you are invoking a method that may throw an exception?
What are exceptions thrown by the .NET platform called?
What is a good .NET class to derive custom exceptions from instead of System.Exception?
What is the default access modifier applied to a non-nested type in .NET?
What optional block can be used with try/catch in C# to ensure that some code will always execute regardless of an exception happening or not?
Pro C# 10 with .NET 6 Chapter 8. Working with Interfaces Study cards

Understanding Interface Types


An interface expresses a behavior that a given class or structure may choose to support. A class or structure can support as many interfaces as necessary.

The .NET Core base class libraries ship with many predefined interface types. It is a best practice when creating your own interfaces to follow the convention of the .NET interface names being prefixed with a capital letter I.

Interface Types vs. Abstract Base Classes


There are only two real differences between interfaces and abstract classes: interfaces cannot have nonstatic constructors, and a class can implement multiple interfaces.

The major limitation that an abstract parent class suffers is that only derived types will support the members defined by the abstract parent. It is common for different classes in different class hierarchies to have to support the same polymorphic interface. Interface types come to the rescue here.

Another limitation of abstract base classes is that each derived type must contend with the set of abstract members and provide an implementation. It may not make sense for certain types to define certain concrete methods, and again interface types provide a solution.

Defining Custom Interfaces


An interface is defined using the interface keyword. Unlike a class, interfaces never specify a base class.

Interfaces as of C# 8 cannot define data fields or nonstatic constructors. This will result in compiler errors:

public interface IPointy
{
  // Error! (It cannot have a data field)
  public int numbOfPoints;

  // Error! (It cannot have a nonstatic constructor)
  public IPointy() { numbOfPoints = 0; }
}

Interface types are able to define any number of property prototypes. They can also contain event and indexer definitions. Interfaces do not do much on their own and really need to be implemented by a class or structure to do anything.

Implementing an Interface


When a class or structure chooses to extend its functionality by supporting interfaces, it does so using a comma-delimited list in the type definition. The direct base class must be the first item listed after the colon operator, unless the type derives directly from System.Object. Given that structures always derive from System.ValueType, simply list each interface directly after the structure definition.

public class Pencil : IPointy
{...}

public class SwitchBlade : object, IPointy
{...}

public class Fork : Utensil, IPointy
{...}

public struct PitchFork : ICloneable, IPointy
{...}

Understand that implementing an interface is an all-or-nothing proposition for interface items that do not include a default implementation. A supporting type cannot selectively choose which members it will implement.

Invoking Interface Members at the Object Level


The most straight forward way to interact with functionality supplied by a given interface is to invoke the members directly from the object level.

Suppose you had an array of types, and only some were compatible with an interface. You might use an explicit cast and handle any thrown InvalidCastException gracefully:

try
{
  itfPt = (IPointy)c;
}
catch (InvalidCastException e)
{
  Console.WriteLine(e.Message);
}

Obtaining Interface References: The as Keyword


You can determine whether a given type supports an interface by using the as keyword. If the object can be treated as the specified interface, you are returned a reference to the interface in question. If not, you receive a null reference.

Hexagon hex2 = new Hexagon("Peter");
IPointy itfPt2 = hex2 as IPointy;
if(itfPt2 != null)
{
  Console.WriteLine("Points: {0}", itfPt2.Points);
}
else
{
  ...
}

When using the as keyword, you do not need to use try/catch logic. If the reference is not null, you known you are calling on a valid interface reference.

Obtaining Interface References: The is Keyword


You may also check for an implemented interface using the is keyword. If the object in question if not compatible with the specified interface, you are returned the value false. If you supply a variable name in the statement, the type is assigned into the variable, eliminating the need to do the type check and perform a cast.

if(hex2 is IPointy itfPt3)
{
  Console.WriteLine("Points: {0}", itfPt3.Points);
}
else
{
  Console.WriteLine("Oops. not pointy");
}

Default Implementations


C# 8 added the ability for interface methods and properties to have a default implementation. If the interface has a default implementation for a property that the class does not, then the class must be cast to the interface in order to call the property. Make sure that you measure the implications of the calling code having to know where the implementation exists.

Static Constructors and Members


C# 8 also added the ability for interfaces to have static constructors and members. These function the same as static members on class definitions but are defined on interfaces.

interface IRegularPointy : IPointy
{
  int SideLength { get; set; }
  int NumberOfSides { get; set; }
  int Perimeter => SideLength * NumberOfSides;

  // Static members are allowed
  static string ExampleProperty { get; set; }

  static IRegularPointy() => ExampleProperty = "Foo";
}

Static constructors must be parameterless and can only access static properties and methods.

Interfaces as Parameters


Methods can take interfaces as parameters. If you define a method to take an interface as a parameter, then the argument can be any object implementing the interface.

Interfaces as Return Values


The type of a return value can also be an interface.

Arrays of Interface Types


IPointy[] myPointyObjects = {new Hexagon(), new Knife(), new Triangle(), new Fork(), new PitchFork()};

When you have an array of a given interface, the array can contain any class or structure that implements the interface.

Implementing Interfaces Using Visual Studio or Visual Studio Code


A new interface can be automatically pulled out from an existing class definition.

Explicit Interface Implementation


Name clashes can be resolved using explicit interface implementation syntax.

class Octagon: IDrawToForm, IDrawToMemory, IDrawToPrinter
{
  // Explicitly bind Draw() implementations to a given interface
  void IDrawToForm.Draw()
  {
    ...
  }
  void IDrawToMemory.Draw()
  {
   ...
  }
}

IDrawToForm itfForm = (IDrawToForm)oct;
itfForm.Draw();

Designing Interface Hierarchies

What type in C# essentially expresses a behavior that a given class or structure may choose to support?
Can classes and structures in C# support more than one interface?
What is the keyword to define an interface in C#?
public struct PitchFork : ICloneable, IPointy {...} What is this C# code showing?
public class Fork : Utensil, IPointy {...} What is this C# code showing?
If you try to cast a type to an interface and the type is not compatible, what exception class is thrown?
IPointy itfPt2 = hex2 as IPointy; What will be itfPt2 if hex2 cannot be treated as the specified interface (C#)?
What category of types in .NET are basically named collections of abstract members?
Pro C# 10 with .NET 6 Chapter 9. Understanding Object Lifetime Study cards
What is the region of memory that .NET objects are allocated to and where they will be automatically destroyed by the garbage collector sometime in the future?
When you use the C# new keyword, the return value is a reference to the object that is stored on the heap. Where is the reference stored?
What is a short and incomplete answer to the question of how the .NET garbage collector knows when an object is no longer needed?
What does the .NET runtime build during a garbage collection process that represents every reachable object on the heap?
What does the managed heap maintain to identify exactly where the next object will be located (C#)?
What will the .NET runtime do if it determines that the managed heap does not have sufficient memory to allocate the requested type when processing a newobj instruction?
How are objects on the managed heap in .NET divided so that the runtime does not have to literally examine every object there?
When the .NET garbage collector investigates the generation 0 objects and finishes getting rid of objects, what happens to any objects that survived?
What happens when the .NET garbage collector examines and gets rid of generation 0 objects that it can but additional memory is still required?
Pro C# 10 with .NET 6 Chapter 10. Collections and Generics Study cards
Nongeneric collections and generic collections are the two broad categories of what in .NET?
ArrayList, BitArray, Hashtable, Queue, SortedList, and Stack from System.Collections are examples of what?
What is the process of explicitly assigning a value type to a System.Object variable, which allocates a new object on the heap and copies the value type's value into that instance?
Why are generics in C# more performant (compared to nongeneric collections)?
Why are generics in C# type-safe (compared to nongeneric collections)?
When you see something like List<T>, what is the pair of angled brackets with a token within called?
What syntax is this an example of? List<int> myGenericList = new List<int> { 0, 1, 2, 3, 4, 5, 6 };
This example is an example blending what two syntaxes of the C# language? List<Point> myListOfPoints = new List<Point> { new Point { X = 2, Y = 2 }, new Point { X = 3, Y = 3 }, new Point { X = 4, Y = 4 } };
What is probably the most frequently used type from the System.Collections.Generic namespace?
Any application you create with .NET will need to manipulate a set of what in memory, that can come from a relational database, a text file, an XML document, a web service call, user-provided input, etc.?
What namespace are nongeneric collections typically found in .NET?
What are the two types of broad categories of data that the .NET Core platform supports?
What mechanism does C# provide to store the data of a value type within a reference variable?
What is it called when you assign a .NET value type to a System.Object variable?
What can you use to avoid the issues of boxing/unboxing performance penalties and lack of type safety of the collections in previous .NET versions?
What generic interface defines general characteristics (e.g., size, enumeration, and thread safety) for all generic collection types?
What generic interface allows a generic collection object to represent its contents using key-value pairs?
What namespace is the generic List<T> class from in .NET?
What is a way you can read the symbol <T> of generic items in .NET?
What is it called when the CoreCLR allocates a new object on the heap to copy a value type's data value into it?
What System.Collections interface defines general characteristics for all nongeneric collection types?
What System.Collections interface provides behavior to add, remove, and index items in a sequential list of objects?
What namespace are generic collections primarily found in .NET?
What notation is the telltale sign of any generic item in .NET?
What are nongeneric containers considered since they are typically designed to operate on System.Object types?
What class from the System.Collections.Generic namespace represents a collection that maintains items using a last-in, first out manner?
What are two members defined by Stack<T> (that you might expect)?
What is the most frequently used type in System.Collections.Generic?
What class from the System.Collections.Generic namespace is useful to model a scenario in which items are handled on a first-come, first-served basis?
What generic interface provides the base interface for the abstraction of sets in .NET?
What generic interface provides behavior to add, remove, and index items in a sequential list of objects in .NET?
What member of Queue<T> is used to remove and return the object at the beginning of the Queue<T>?
What member of Queue<T> is used to add an object to the end of the Queue<T>?
What member of Queue<T> is used to return the object at the beginning of the Queue<T> without removing it?
What type in System.Collections.ObjectModel represents a dynamic data collection that has the ability to inform external objects when its contents have changed in some way?
Pro C# 10 with .NET 6 Chapter 11. Advanced C# Language Features Study cards
What type of method can you implement for a C# class that enables you to provide access to internal subitems using an array-like syntax?
What keyword must be used in .NET to declare an anonymous type?
What syntax must be used in .NET to declare an anonymous type?
What type of type can be used to quickly model the "shape" of data with little overhead in .NET?
What type do anonymous types automatically derive from in .NET?
What is the syntax for creating an indexer method in C#?
What is an example of how you might overload the + operator in C# in a Point class?
What are the first two or three restrictions when defining an extension method in C#?
If you had a Square and Rectangle class in a C# app and wanted to be able to write the following code: Square s = (Square)rectangle What example code might you have in the Square class?
What was introduced in .NET to allow adding new methods or properties to a class or structure without modifying the original type in any direct manner?
What is the keyword and syntax used in C# to declare an anonymous type?
All anonymous types in C# automatically derive from what class?
Pro C# 10 with .NET 6 Chapter 12. Delegates, Events, and Lambda Expressions Study cards
What is the C# lambda operator?
What is the type in C# that is the preferred means of defining and responding to callbacks in applications?
What were the C-style function pointers historically used by the Windows API to configure a function to report back to another function?
What are "nothing more than a concise way to author anonymous methods and ultimately simplifying how you work with the .NET delegate type?"
What do C# delegates have support for that traditional C++ function pointers do not?
What is C#'s token for the lambda operator found in lambda calculus?
What type in .NET and .NET Core is able to do what callbacks did before in a type-safe and object-oriented manner?
When you build a type using the C# delegate keyword, you are indirectly declaring a class type that derives from what class?
What type from the System namespace is a generic delegate that can "point to" a method that takes up to 16 arguments and returns void?
What type is similar to Action<> but it can point to methods that have a custom return value?
What is the class that derives from System.Delegate and provides the necessary infrastructure for a C# delegate to hold onto a list of methods to be invoked later?
What is the main requirement when defining a delegate type in C#?
What can a delegate do in .NET once it has been created and given the necessary information?
What type is the preferred means of defining and responding to callbacks within apps under the .NET platform?
What is the C# lambda operator?
What type in .NET is a type-safe object that "points to" a method or a list of methods that can be invoked later?
What type in .NET is a type-safe object that "points to" a method or a list of methods that can be invoked later?
When creating a delegate in C#, what is the main requirement that must be met when defining it?
When the C# compiler processes delegate types, it automatically generates a sealed class derived from what class that allows the delegate to hold onto a list of methods to invoke later?
When you build a type using the C# delegate keyword, you are indirectly declaring a class that derives from what type?
Pro C# 10 with .NET 6 Chapter 13 LINQ to Objects Study cards
The Language Integrated Query (LINQ) technology set provides a concise, symmetrical, and strongly typed manner to access a variety of data stores. First a review of the key C# programming constructs that enable LINQ.

LINQ-Specific Programming Constructs


At a high level, LINQ can be understood as a strongly typed query language embedded directly into the grammar of C#.

Implicit Typing of Local Variables


The var keyword of C# allows you to define a local variable without explicitly specifying the underlying data type. The variable is still strongly typed as the compiler will determine the correct data type based on the initial assignment. Many LINQ queries will return a sequence of data types which are not known until compile time.

Object and Collection Initialization Syntax


Object initialization syntax allows you to create a class or structure variable and set any number of its public properties in one fell swoop. This results in a compact and easy on the eyes syntax to prepare objects. C# also allows you to use a similar syntax to initialize collections of objects. This snippet uses collection initialization syntax to fill a List<T> of Rectangle objects:

List<Rectangle> myListOfRects = new List<Rectangle>
{
  new Rectangle {TopLeft = new Point { X = 10, Y = 10},
                 BottomRight = new Point { X = 200, Y = 200}},
  new Rectangle {TopLeft = new Point { X = 2, Y = 2 },
                 BottomRight = new Point { X = 100, Y = 100}},
  new Rectangle {TopLeft = new Point { X = 5, Y = 5 },
                 BottomRight = new Point { X = 90, Y = 75}}
};

When combined with implicit typing of local variables, this also allows you to declare an anonymous type which is useful when creating a LINQ projection.

Lambda Expressions


=> is the C# lambda operator. This operator allows you to build a lambda expression, which can be used any time you invoke a method that requires a strongly typed delegate as an argument. Lambdas greatly simplify how you work with delegates in that they reduce the amount of code you must author by hand. A lambda expression can be broken down into the following usage:

( ArgumentsToProcess ) => { StatementsToProcessThem }

List<int> list = new List<int>();
list.AddRange(new int[] { 20, 1, 4, 8, 9, 44 });
List<int> evenNumbers = list.FindAll(i => (i % 2) == 0);
What is the unabbreviated form of LINQ?
What provides a concise, symmetrical, and strongly typed manner to access a variety of data stores in C#?
What can be understood as a strongly typed query language embedded directly into the grammar of C#?
What keyword in C# allows you to define a local variable without explicitly specifying the underlying data type?
Some functionality of the LINQ to Objects API can only be accessed by calling extension methods of what class?
What type defines the various extension methods that the LINQ query operators such as from, in, where, orderby, select are shorthand for?
When LINQ Queries are compiled, the C# compiler translates all C# LINQ operators into calls on methods of what class?
What generic delegate type have "a great many" of the methods of Enumerable been prototyped to take as arguments (LINQ)?
What term refers to the act of applying LINQ queries to arrays and collections?
What term refers to the act of using LINQ to manipulate and query XML documents?
What term refers to an aspect of LINQ that lets you use LINQ queries with the ADO.NET EF Core API?
What term refers to parallel processing of data returned from a LINQ query?
The words from, in, where, orderby, and select are examples of what in C#?
What specific syntax of LINQ is this? IEnumerable<string> subset = from game in currentVideoGames where game.Contains(" ") orderby game select game;
What specific syntax of LINQ is this? IEnumerable<string> subset = currentVideoGames.Where(g => g.Contains(" ")).OrderBy(g => g).Select(g => g);
What will you always want to make use of when capturing the results of a LINQ query in C#?
What is the type of the return value (the generic interface that it implements) of a LINQ query (most of the time)?
What is it called that describes how LINQ query expressions that return a sequence do not actually evaluate until you iterate over the resulting sequence?
What is a thing to note about a LINQ statement that selects a single element (such as by using First()/FirstOrDefault()/Single()/SingleOrDefault()) regarding execution?
What is the difference between First()/FirstOrDefault() and Single()/SingleOrDefault()?
What are the three operators that every LINQ query expression is built from?
What is the general template for a LINQ query expression using the operators from, in, and select?
What is the general template for a LINQ query expression using the three basic operators and also where to obtain a specific subset?
What is the extension method that can be used with the result of a LINQ query to remove duplicate entries?
What is one (or a couple) example of an extension method that can be used with LINQ queries to perform an aggregation operation on the result set?
Pro C# 10 with .NET 6 Chapter 14. Processes, AppDomains, and Load Contexts Study cards
Application domains (or simply AppDomains) are logical subdivisions within a given process that host a set of related .NET Core assemblies. An AppDomain is further subdivided into contextual boundaries which are used to group like-minded .NET Core objects.

It is important to understand processes, AppDomains, and object contexts when working with numerous .NET Core APIs including multithreading, parallel processing, and object serialization.

The Role of a Windows Process


A process is a running program, in simple terms. Formally speaking, a process is an operating system-level concept used to describe a set of resources and the necessary memory allocations used by a running application. For each .NET Core application loaded into memory, the OS creates a separate and isolated process for use during its lifetime. The process can be regarded as a fixed, safe boundary for a running application.

The Role of Threads


Every Windows process contains an initial "thread" that functions as the entry point for the application. A thread is a path of execution within a process. The first thread created by a process's entry point is termed the primary thread. The primary thread is created when the Main() method (or file with top level statements) is invoked.

Processes that contain a single primary thread of execution are intrinsically thread-safe. A single-thread could have the drawback of seeming unresponsive to the user if it were performing a complex operation.

The operating systems supported by .NET Core make it possible for the primary thread to spawn additional secondary threads, which are called worker threads, using a handful of API functions such as CreateThread(). Each thread becomes a unique path of execution in the process and has concurrent access to all shared points of data within the process.

Developers typically create additional threads to improve the program's overall responsiveness. But, using too many threads in a single process can potentially degrade performance, due to the CPU siwtching between the active threads which takes time.

On some machines, multithreading is most commonly an illusion provided by the OS. Machines that host a single, nonhyperthreaded CPU do not have the ability to literally handle multiple threads. The CPU will execute a thread for a unit of time called a time slice based in part on the thread's priority level. When the thread's time slice is up, the existing thread is suspended so that another thread can perform its business. To remember what was happening before it was kicked out of the way, each thread is given the ability to write to Thread Local Storage (TLS) and is provided with a separate call stack.



If you don't want to sweat the details, just remember that a thread is a unique path of execution within a Windows process. Every process has a primary thread and may contain additional threads that have been programmatically created.

Interacting with Processes Using .NET Core


The System.Diagnostics namespace defines several types that allow you to programmatically interact with processes and various diagnostic-related types such as the system event log and performance counters.



The System.Diagnostics.Process class allows you to analyze the processes running on a given machine (local or remote). Process also provides members to programmatically start and terminate processes, change the priority levels of threads, and obtain a list of active threads.



Process also defines a few useful methods:

Enumerating Running Processes


static void ListAllRunningProcesses()
{
  // Get all processes on the local machine, ordered by PID
  var runningProcs =
    from proc
    in Process.GetProcesses(".")
    orderby proc.Id
    select proc;

  // Print out PID and name of each process
  foreach(var p in runningProcs)
  {
    string info = $"-> PID: {p.Id}\tName: {p.ProcessName}";
    Console.WriteLine(info);
  }
}

Process.GetProcesses() returns an array of Process objects that represent the running processes on the target machine. The dot notation here represents the local computer.

Investigating a Specific Process


You can get a single process by its associated PID using Process.GetProcessById().

Investigating a Process's Thread Set


The set of threads is represented by the strongly typed ProcessThreadCollection collection, which contains some number of ProcessThread objects.

theProc = Process.GetProcessById(pID);
ProcessThreadCollection theThreads = theProc.Threads;

foreach(ProcessThread pt in theThreads)
{
  ...
}



Note that the ProcessThread type is not used to create, suspend, or kill threads in .NET. It is just for getting diagnostic information.

Investigating a Process's Module Set


When talking about processes, a module is a general term used to describe a given *.dll (or the *.exe itself) that is hosted by a specific process. When you access the ProcessModuleCollection via the Process.Modules property, you can enumerate over all modules hosted within a process which can include traditional C-based libraries in addition to .NET Core-based.

Starting and Stopping Processes Programmatically


The Start() and Kill() methods of the System.Diagnostics.Process class provide a way to programatically launch and terminate a process.

proc = Process.Start(@"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe", "www.facebook.com");

foreach (var p in Process.GetProcessesByName("MsEdge"))
{
  p.Kill(true);
}

The static Process.Start() method is overloaded, and at minimum, you need to specify the path and the filename of the process you want to launch. It returns a reference to the newly activated process which can be killed using the instance-level method Kill().

Controlling Process Startup Using the ProcessStartInfo Class


Process.Start() allows you to pass in a System.Diagnostics.ProcessStartInfo type that specifies additional information regarding how a process should come to life.

Leveraging OS Verbs with ProcessStartInfo


ProcessStartInfo can be used to take advantage of file associations.

Understanding .NET Application Domains


Under the .NET and .NET Core platforms, executables are not hosted directly within a Windows process. Rather, .NET and .NET Core executables are hosted by a logical partition within a process called an application domain.

AppDomains are a key aspect of the OS-neutral nature of the .NET Core platform. This logical division abstracts away the differences in how the underlying OS represents the loaded executable.

AppDomains are also less expensive in terms of CPU and memory than a full-blown process.

AppDomains are fully and completely isolated from other AppDomains within a process. An application running in one AppDomain is unable to obtain data of any kind from another AppDomain, unless they use a distributed programming protocol.

In .NET Core, there is exactly one AppDomain. The ApplicationLoadContext provides assembly isolation in .NET Core.

The System.AppDomain Class


The AppDomain is largely deprecated with .NET Core.

Interacting with the Default Application Domain


Your application has access to the default application domain using the static AppDomain.CurrentDomain property.

Enumerating Loaded Assemblies


AppDomain defaultAD = AppDomain.CurrentDomain;

Assembly[] loadedAssemblies = defaultAD.GetAssemblies();

Assembly Isolation with Application Load Contexts


AppDomains are logical partitions used to host .NET Core assemblies. An application domain can be further subdivided into numerous load context boundaries. Conceptually, a load context creates a scope for loading, resolving, and potentially unloading a set of assemblies. In a nutshell, a .NET Core load context provides a way for a single AppDomain to establish a "specific home" for a given object.
What can be regarded as a fixed, safe boundary for a running application?
What are logical subdivisions within a given .NET process?
In really simple terms, what is a process?
What is uniquely assigned to every Windows process?
What formally speaking is an operating system-level concept that is a set of resources and the necessary allocations used by a running application?
On machines with a single (nonhyperthreaded) CPU that cannot literally handle more than one thread at a time, the single CPU executes one thread for a unit of time based in part on the thread's priority level, and then suspend that thread to allow another thread to do some work. The unit of time is called a what?
What namespace and class in .NET allows you to analyze the processes on a given machine (local or remote) and programmatically start and stop processes?
What namespace and class in .NET represents a thread within a given process (it is used to diagnose a process's thread set, and is not used to spawn new threads in a process)?
What type provides a strongly typed collection of ProcessThread objects in the System.Diagnostics namespace?
What property of the System.Diagnostics.Process type provides access to the ProcessThreadCollection class?
What property of the ProcessThread type gets the current priority of the thread?
What property of the ProcessThread type sets the preferred processor for the thread to run on?
What property of the ProcessThread type is used to get or set the priority level of the thread?
What property of the ProcessThread type gets the memory address of the function that the operating system called that started the thread?
.NET executables are hosted by a logical partition within a process called a what?
What key aspect of the OS-neutral nature of .NET abstracts the differences in how an underlying OS represents a loaded executable?
What are far less expensive in terms of processing power and memory than full-blown processes and thus allow the CoreCLR to load and unload things faster than a formal process and improve server app scalability?
A .NET process application domain is capable of hosting and executing any number of related what (answer is not contextual boundaries)?
How many AppDomains can be in a process (as of .NET Core)?
What is a general term used to describe a given *.dll (or the *.exe itself) that is hosted by a specific process?
What type is a vehicle to obtain diagnostic information for the active Windows threads within a running process (and not used to create multithreaded apps)?
What static method of System.Diagnostics.Process returns a new Process object that represents the currently active process?
What property of System.Diagnostics.Process gets the PID of the associated process?
What property of System.Diagnostics.Process gets the name of the computer that the associated process is running on?
What property of System.Diagnostics.Process gets the name of the process ("which, as you would assume, is the name of the application itself")?
What property of System.Diagnostics.Process gets a value indicating whether the user interface of the process is responding to user input (or is currently "hung")?
What property of System.Diagnostics.Process returns a collection of ProcessThread objects?
What static method of System.Diagnostics.Process returns an array of new Process objects running on a given machine?
What method of System.Diagnostics.Process closes a process that has a user interface by sending a close message to its main window?
What method of System.Diagnostics.Process immediately stops the associated process?
What is a path of execution within a process?
What is the keystroke combo to active the Window Task Manager utility?
How are application domains further divided (.NET)?
What is used to group like-minded .NET objects inside of an AppDomain?
What is a logical subdivision within a given process that hosts a set of related .NET assemblies (in a nutshell)?
A .NET AppDomain is further subdivided into what (which are used to group like-minded .NET objects)?
What term refers to the initial thread of a process, that would be created when the Main() method of a C# project was invoked?
A process that contains only a single primary thread intrinsically is what?
When a process spawns additional secondary threads, what are those threads called?
What always has a primary thread, and may contain additional threads that have been programmatically created?
Pro C# 10 with .NET 6 Chapter 15 Multithreaded, Parallel, and Async Programming Study cards
Who enjoys using an app that is really slow?
What can be defined as a path of execution within an executable application?
Spawning additional threads will not necessarily make applications faster on what type of machines?
What namespace released with .NET 1.0 offers one approach to building multithreaded applications?
When you write code that creates a new thread, can you guarantee that the thread executes immediately?
What namespace in .NET provides types that enable the direct construction of multithreaded apps?
What type in System.Threading represents a thread that executes within the .NET runtime and can be used to spawn additional threads in the originating AppDomain?
What type in System.Threading provides a mechanism for executing a method at specified intervals?
What type in System.Threading allows you to limit the number of threads that can access a resource concurrently?
What most primitive type in System.Threading represents an object-oriented wrapper around a given path of execution within an AppDomain?
What instance-level member of System.Threading.Thread returns a bool that indicates if the thread has been started (and has not yet terminated or aborted)?
What instance-level member of System.Threading.Thread gets or sets a value that indicates whether the thread is a background thread?
What instance-level member of System.Threading.Thread instructs the .NET runtime to terminate the thread as soon as possible?
What is a good property to set on a System.Threading.Thread instance that will greatly simplify your debugging endeavors?
What instance-level member of System.Threading.Thread instructs the .NET runtime to start the thread as soon as possible?
What will happen if you decorate a method with the async keyword but that method does not have an internal await method call?
What keywords can you use in .NET that will make the compiler generate a good deal of threading code on your behalf?
What static method of System.Threading.Thread suspends the current thread for a specified time?
What type in System.Threading is a delegate type used in conjunction with Timer?
What type in System.Threading allows you to interact with the .NET runtime-maintained thread pool within a given process?
What are threads that can prevent the current app from terminating?
What are threads that are viewed by the .NET runtime as expendable paths of execution that can be ignored at any point in time?
The .NET runtime will not shut down an app until all of what kind of thread have ended?
What are sometimes called daemon threads?
What issue can be described as the possibility of different threads changing the value of any shared data?
What type and delegate can you use in .NET when you need a function to be called every so often by the app (especially for noncritical background tasks like checking for new emails)?
The types of what namespace are collectively referred to as the Task Parallel Library?
What newer approach to multithreaded app development (newer than System.Threading) did Microsoft introduce with .NET 4.0?
What C# keyword qualifies that a method, lambda expression, or anonymous method should be called in an asynchronous manner automatically?
What can you use to mark a method with that will cause the .NET Core runtime to create a new thread of execution to handle the task at hand?
What C# keyword makes the current thread be paused when an asynchronous method is called?
What type of method call do you have if you have a method decorated with the async keyword and it contains no internal await?
If you have a Main() method in Program.cs that returns an int, and you want to decorate Main() with async, what will the new return type be?
What two keywords were added in .NET 4.5 that further simplified the process of writing asynchronous code?
What type does System.Threading provide to interact with the runtime thread pool?
Pro C# 10 with .NET 6 Chapter 16. Building and Configuring Class Libraries Study cards
What is the most commonly used file format for configuring .NET applications (previously it was XML)?
What type from Microsoft.Extensions.Configuration has methods SetBasePath() and AddJsonFile()?
What is a second use of the C# using keyword (the primary way being to use a type from a different namespace)?
What class library project was introduced with .NET Core 1.0 to help with a situation where you have significant shared code already written in .NET Framework and want to start using new .NET?
What is the platform and CPU agnostic code at the core of a .NET assembly?
An instance of what type is returned by the Build() method of ConfigurationBuilder?
What are pieced together into .NET apps?
What is a versioned, self-describing binary hosted by the .NET runtime?
What does the Pro C# book call a "code library" corresponding to a *.dll that contains types intended to be used by external applications?
If you have a code library in C#, what are the languages you can reuse it in?
Why are .NET assemblies a supreme form of code reuse?
As an example of cross-language code reuse, an interface in F# would be implemented by what in C#?
What is "perfectly possible (although certainly not common)?"
How similar are .NET assemblies and previous *.dll Windows binaries internally?
What do .NET assemblies promote according to the Pro C# book?
What node do you add to a *.csproj file to name the root namespace?
What feature did C# 10 add related to namespaces?
What is the base namespace named after the project and a single class, Program in C#?
What namespace is the IO namespace nested in (.NET)?
How do the Visual Studio property pages refer to the root namespace?
{ "CarName": "Suzy", "Car": { "Make":"Honda", "Color": "Blue", "PetName":"Dad's Taxi" } } What would be the method call on the IConfiguration instance to get the PetName of the Car from this?
What is the method of IConfiguration to get an entire section from the configuration JSON?
What feature added in C# 10 allowed removing about 2 pages per chapter in the Pro C# book?
What is a type's name prefixed with the defining namespace (C#)?
What can be helpful (and sometimes necessary) when using multiple namespaces that have identically named types (C#)?
What is the most commonly used syntax for creating nested namespaces (C#)?
What is a common practice with C# namespaces that can make the namespace structure clearer to other developers?
What file can you edit to configure the root namespace of a .NET project?
What is a versioned, self-describing binary file hosted by the .NET runtime?
What are pieced together to construct a .NET app?
What is the blob of metadata that an assembly has that describes the assembly itself?
What consists of an operating system file header, a CLR file header, CIL code, type metadata, an assembly manifest, and optional embedded resources?
What are unlike .NET console applications in that they do not have an entry point and cannot be launched directly?
What does the Pro C# book call a name-value pair format where each object is enclosed in curly braces?
What keyword specifies that a type can be used only by the assembly in which they are defined?
What is this command adding? dotnet add CSharpCarClient reference CarLibrary
What aspect of .NET development is illustrated by a Visual Basic class deriving from a class authored in C#?
What is the package manager for .NET?
What term refers to packaging up your app and its related dependencies?
What way of publishing a .NET app means .NET will not need to be installed on the target machine?
What must you specify in the project file or through the command-line options when publishing .NET apps as self-contained?
How will the publish process be by default for a .NET application where the runtime identifier has been specified?
What short option to dotnet publish is the output directory to place the published artifacts in?
What long option to dotnet publish will make the .NET runtime be published with the app?
What argument to the short option -r of dotnet publish means 64-bit Windows?
What process that occurs during publishing a .NET app determines what can be removed based on what your app really uses?
What folder in Windows is where the Pro C# book says is where the .NET runtime and framework files are installed?
What does the runtime host provides that are used when a version of the .NET runtime is started to find an application's dependencies?
What does the Pro C# book call .NET binaries that contain logic intended to be reused across a variety of projects?
What long option to dotnet publish will make the app be published as a framework-dependent application without the .NET runtime?
What is the command in the .NET CLI for publishing applications?
What is the verb that means packaging up your application and its related dependencies to give it to your users?
What type of .NET app deployment requires the framework to be installed on the target machine?
What type of .NET app does not require .NET to be installed on the target machine?
What option to dotnet publish causes the .NET runtime to be published with the app so that the runtime doesn't need to be installed on the target machine?
Pro C# 10 with .NET 6 Chapter 17. Type Reflection, Late Binding, Attribute, and Dynamic Types Study cards
What are the basic units of deployment in the .NET universe?
What namespace is useful for programmatically obtaining information that you would be able to investigate at design-time like types within a project's referenced assemblies, underlying CIL code, type metadata, and assembly manifests?
Pro C# 10 with .NET 6 Chapter 19. File I/O and Object Serialization Study cards
What is the region of the .NET base class libraries devoted to file-based (and memory-based) input and output (I/O) services?
What in I/O manipulation represents a chunk of data flowing between a source and a destination?
What, as a concept, is a sequence of bytes?
What provides a common way to interact with a sequence of bytes regardless of the type of device that stores or displays the bytes (file, network connection, printer, etc.)?
What term refers to the process of persisting the state of an object into a stream?
System.IO is a namespace in .NET relating to what kinds (2) of services?
What class in .NET (in System.IO) provides temporary storage for a stream of bytes that you can commit to storage later?
What class in System.IO for manipulating a machine's directory structure exposes functionality through static members only?
What class in System.IO for manipulating a machine's directory is used to make objects (instances)?
What class in System.IO provides detailed information about the drives that a given machine uses?
What class in System.IO for manipulating a machine's set of files exposes functionality through static members only?
What formatter from System.Text.Json can be used to persist the public state of an object as JSON?
What class in System.IO for manipulating a machine's set of files is used to make objects (instances)?
What class in System.IO gives you random file access (e.g., seeking capabilities) with data represented as a stream of bytes?
What is the abstract class which is the parent of DirectoryInfo and FileInfo in System.IO?
What member of FileSystemInfo has the name of the file or directory (C#)?
What member of FileSystemInfo has the full path of the file or directory (C#)?
What member of DirectoryInfo is used to delete a directory and all of its contents?
What member of DirectoryInfo is used to move a directory and its contents to a new path?
Pro C# 10 with .NET 6 Chapter 20. Data Access with ADO.NET Study cards
What refers to several namespaces in .NET that allow you to work with relational database systems?
What in ADO.NET is a set of types defined in a namespace for communicating with a specific database management system?
Pro C# 10 with .NET 6 Chapter 21. Introducing Entity Framework Core Study cards
The previous chapter was about ADO.NET. ADO.NET enables .NET programmers to work with relational data. ADO.NET is an effective tool for working with data but is not necessarily good in developer efficiency. Microsoft introduced the Entity Framework to help with the developer efficiency.

EF allows interacting with data from relational databases using an object model that maps to the business objects (or domain objects) in your application. You can operate on a collection of strongly typed objects called entities. They are held in specialized collection classes that are LINQ aware. The collection classes provide querying against the data store using the LINQ grammar.

EF also provides efficiencies like state tracking, unit of work operations, and intrinsic transaction support.

Entity Framework Core is a complete rewrite of Entity Framework 6. EF Core can be used to scaffold entity classes and a derived DbContext from an existing database, or it can be used to create and update the database from entity classes and derived DbContext.

Object-Relational Mappers


Object-relational mapping frameworks in .NET manage the bulk of CRUD data access tasks for the developer. The developer creates a mapping between the .NET objects and the relational database. The ORM manages connections, query generation, change tracking, and persisting the data. ORMs can introduce performance and scaling issues if used improperly. Use ORMs for CRUD operations and the database for set-based operations.

The different ORMs have slight differences in how they operate and are used but have essentially the same parts. Entities are classes that are mapped to the database tables. A specialized collection type contains one or more entities. A change tracking mechanism tracks the state of the entities and any changes, additions, or deletions made to them. A central construct controls operations as the ringleader.

Understanding the Role of the Entity Framework Core


EF Core uses ADO.NET under the hood. EF Core is best used in forms-over-data (or API-over-data) situations. It is not very well suited for large-scale data operations such as extract-transform-load (ETL) data warehous applications or large reporting situations.

The Building Blocks of the Entity Framework


The main components of EF Core are DbContext, ChangeTracker, the DbSet specialized collection type, the database providers, and the application's entities. The common functionality for EF Core is provided by the Microsoft.EntityFrameworkCore package. Microsoft.EntityFrameworkCore.Design is required for the EF Core command-line tools.

A GlobalUsings.cs might look like the following:

global using Microsoft.EntityFrameworkCore;
global using Microsoft.EntityFrameworkCore.ChangeTracking;
global using Microsoft.EntityFrameworkCore.Design;
global using Microsoft.EntityFrameworkCore.Metadata;
global using Microsoft.EntityFrameworkCore.Metadata.Builders;

global using System.ComponentModel.DataAnnotations;
global using System.ComponentModel.DataAnnotations.Schema;

The DbContext Class


The DbContext class is the ringleader component of EF Core and provides access to the database through the Database property. DbContext manages the ChangeTracker instance, exposes the virtual OnModelCreating() method for access to the Fluent API, holds all the DbSet<T> properties, and supplies the SaveChanges method to persist data to the data store. It is not used directly, but through a custom class that inherits DbContext. It is in the derived class that the DbSet<T> properties are placed.





Creating a Derived DbContext


The first step in EF Core is to create a custom class that inherits from DbContext. Then add a constructor that accepts a strongly typed instance of DbContextOptions and passes the instance through to the base class. This is an example ApplicationDbContext.cs file:

namespace AutoLot.Samples;

public class ApplicationDbContext : DbContext
{
  public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)
  {
  }
}

Configuring the DbContext


The DbContext instance is configured using an instance of the DbContextOptions class, which is created using the DbContextOptionsBuilder. This allows selecting the database provider (and any provider-specific settings) and EF COre DbContext general options. The DbContextOptions instance is injected into the base DbContext at runtime.

The Design-Time DbContext Factory


The design-time DbContext factory is a class that implements the IDesignTimeDbContextFactory<T> interface where T is the derived DbContext class. The interface has one method: CreateDbContext(). You must implement this method to create an instance of your derived DbContext. This is only meant to be used during development.

namespace AutoLot.Samples;

public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
  public ApplicationDbContext CreateDbContext(string[] args)
  {
    var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
    var connectionString = @"..."
    optionsBuilder.UseSqlServer(connectionString);
    Console.WriteLine(connectionString);
    return new ApplicationDbContext(optionsBuilder.Options);
  }
}

OnModelCreating


The base DbContext class exposes the OnModelCreating method that is used to shape your entities using the Fluent API. For now, note that this will involve the following code in the derived DbContext class:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  // Fluent API calls go here
}

Saving Changes


Call SaveChanges() (or SaveChangesAsync()) on the derived DbContext to persist any changes to entities. This wraps the database calls in an implicit transaction.

Transaction and Save Point Support


For more control, you can enlist the derived DbContext into an explicit transaction.

Explicit Transactions and Execution Strategies


Saving/Saved Changes Events


The SavingChanges event fires when SaveChanges() is called but before the SQL statements are executed. SavedChanges fires after SaveChanges() has completed.

The DbSet<T> Class


For each entity type (T) in your object model, add a property of type DbSet<T> to the derived DbContext class. The DbSet<T> class is a specialized collection property used to interact with the database provider to read, add, update, or delete records in the database. Each DbSet<T> provides a number of core services for the database interactions, including translating LINQ queries against a DbSet<T> into the database queries.



The DbSet<T> type implements IQueryable<T> which enables the use of LINQ queries to retrieve records from the database. DbSet<T> also supports extension methods you would have learned in Chapter 13 like ForEach(), Select(), and All().

It is much more common to use the methods on the DbSet<T> properties than the more general methods on the derived DbContext.

The ChangeTracker


The ChangeTracker instance tracks the state for objects loaded into DbSet<T> within a DbContext instance.



If you need to check the state of an object:

EntityState state = context.Entry(entity).State;

ChangeTracker Events


There are two events that can be raised by ChangeTracker. The first is StateChanged and the second is Tracked. The StateChanged event fires when an entity's state is changed, but not when an entity is first tracked. The Tracked event fires when an entity starts being tracked.

The constructor of the derived DbContext class can be updated to specify event handlers for the StateChanged and Tracked events:

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
  : base(options)
{
...
  ChangeTracker.StateChanged += ChangeTracker_StateChanged;
  ChangeTracker.Tracked += ChangeTracker_Tracked;
}

The StateChanged Event


This example shows how to write to the console anytime an entity is updated:

private void ChangeTracker_StateChanged(object sender, EntityStateChangedEventArgs e)
{
  if (e.OldState == EntityState.Modified && e.NewState == EntityState.Unchanged)
  {
    Console.WriteLine($"An entity of type {e.Enttry.Entity.GetType().Name} was updated.");
  }
}

The Tracked Event


Resetting DbContext State


EF Core 5 added the ability to reset a derived DbContext back to its original state. The ChangeTracker.Clear() method clears out all entities from the DbSet<T> collections by setting their state to Detached. The main benefit of this is to improve performance.

Entities


The strongly typed classes that map to database tables are officially called entities. The collection of entities in an application comprises a conceptual model of a physical database. This model is termed an entity data model but is usually referred to as the model. Entities do not need to map directly to the database schema.

Entity Properties and Database Columns


EF Core uses data from a table's columns to populate an entity's properties when reading from the data store and writes from the entity's properties to a table's columns when persisting data. If the property is an automatic property, EF Core reads and write through the getter and setter. If the property has a backing field, EF Core will read and write to the backing field instead of the public property, even if the backing field is private.

Table Mapping Schemes


There are two class to table mapping schemes available in EF Core: table-per-hierarchy (TPH) and table-per-type (TPT). TPH mapping is the default and maps an inheritance hierarchy to a single table. TPT maps each class in the hierarchy to its own table.

Classes can also be mapped to views and raw SQL queries. These are called query types.

Table-Per-Hierarchy Mapping


The entire hierarchy becomes a single table.

To make EF Core aware that an entity class is part of the object model, add a DbSet<T> property for the entity.

public class ApplicationDbContext : DbContext
{
  public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options) { }
  public DbSet<Car> Cars { get; set; }
}

The DbSet<T> property in the ApplicationDbContext class informs EF Core that the Car class maps to the Cars table in the database.

Table-per-Type Mapping


Since TPH is the default, EF Core must be instructed to map each class to a table. This can be done with data annotations or the Fluent API. The following Fluent API code specifies using the TPT mapping scheme:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<BaseEntity>().ToTable("BaseEntities");
  modelBuilder.Entity<Car>().ToTable("Cars");
}

Table-per-type mapping can have significant performance implications that should be considered before its use. See the docs.

Navigation Properties and Foreign Keys


Navigation properties represent how entity classes relate to each other and enable code to traverse from one entity instance to another. By definition, a navigation property is any property that maps to a nonscalar type as defined by the database provider. In practice, navigation properties map to another entity (called reference navigation properties) or a collection of another entity (called collection navigation properties). On the database side, navigation properties are translated into foreign key relationships between tables. EF Core directly supports one-to-one, one-to-many, and many-to-many relationships. Entity classes can also have navigation properties that point back to themselves.



Missing Foreign Key Properties


If an entity with a reference navigation property deos not have a property for the foreign key value, EF Core will create a shadow foreign key property.

One-to-Many Relationships


The principal (one side) adds a collection property of the dependent entity class (the many side). The dependency entity should also have properties for the foreign key back to the principal.

public abstract class BaseEntity
{
  public int Id { get; set; }
  public byte[] TimeStamp { get; set; }
}

public class Make : BaseEntity
{
  public string Name { get; set; }
  public IEnumerable<Car> Cars { get; set; } = new List<Car>();
}

public class Car : BaseEntity
{
  public string Color { get; set; }
  public string PetName { get; set; }
  public int MakeId { get; set; }
  public Make MakeNavigation { get; set; }
}

Adding the suffix Navigation to the reference navigation properties for clarity is a style decision.

The following properties must be added to the ApplicationDbContext:

public DbSet<Car> Cars { get; set; }
public DbSet<Make> Makes [ get; set; }

One-to-One Relationships


In one-to-one relationships, both entities have a reference navigation property to the other entity. EF Core must be informed which side is the principal entity for a one-to-one relationship. This can be done by having a clearly defined foreign key to the principal entity or by indicating the principal using the Fluent API.

public class Radio : BaseEntity
{
  public bool HasTweeters { get; set; }
  public bool HasSubWoofers { get; set; }
  public string RadioId { get; set; }
  public int CarId { get; set; }
  public Car CarNavigation { get; set; }
}

public class Car : BaseEntity
{
  public Radio RadioNavigation { get; set; }
}

Car here is the principal entity because Radio has a foreign key to the Car class.

This must be added to the ApplicationDbContext class:

public DbSet<Radio> Radios { get; set; }

Many-to-Many Relationships


Both entities have a collection property to the other entity. This is implemented in the data store with a join table between the two entity tables. The name can be changed programmatically through the Fluent API. The join entity has one-to-many relationships to each of the entity tables.

public class Driver : BaseEntity
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public IEnumerable<Car> Cars { get; set; } = new List<Car>();
}

public class Car : BaseEntity
{
  public string Color { get; set; }
  public string PetName { get; set; }
  public int MakeId { get; set; }
  public Make MakeNavigation { get; set; }
  public Radio RadioNavigation { get; set; }
  public IEnumerable<Driver> Drivers { get; set; } = new List<Driver>();
}

Many-to-Many Prior to EF Core 5


The three tables can also be created explicitly and it must be done this way in EF Core versions earlier than EF Core 5. An abbreviated example:

public class Driver
{
...
  public IEnumerable<CarDriver> CarDrivers { get; set; }
}

public class Car
{
...
  public IEnumerable<CarDriver> CarDrivers { get; set; }
}

public class CarDriver
{
  public int CarId {get;set;}
  public Car CarNavigation {get;set;}
  public int DriverId {get;set;}
  public Driver DriverNavigation {get;set;}
}

Cascade behavior


Optional Relationships


Required Relationships


Entity Conventions


The conventions are always enabled unless overruled by data annotations or code in the Fluent API.



Mapping Properties to Columns


By convention, the public read-write properties map to columns of the same name. The data type matches the data store's equivalent of the property's CLR data type. Non-nullable properties are set to not null in the data store, and nullable properties (including nullable reference types) are set to allow null.

Overriding EF Core Conventions


New in EF Core 6, the conventions can be overriden using the ConfigureConventions() method. For example, to make string properties default to a certain size:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
  configurationBuilder.Properties<string>().HaveMaxLength(50);
}

Entity Framework Data Annotations


Data annotations are C# attributes that are used to further shape your entities. Data annotations override any conflicting conventions.





Annotations and Navigation Properties


The ForeignKey annotation lets EF Core know which property is the backing field for the navigation property. The InverseProperty informs EF Core of how the entities related by indicating the navigation property on the other end. It also makes the code more readable.

The Fluent API


The Fluent API configures the application entities through C# code. The methods are exposed by the ModelBuilder instance available in the DbContext OnModelCreating() method. The Fluent API is the most powerful of the configuration methods and overrides any conventions or data annotations taht are in conflict.

Class and Property Methods


The Fluent API is a superset of the data annotations when shaping your individual entities.

Class and Property Mapping


This is an example using data annotations:

[Table("Inventory", Schema="dbo")]
[Index(nameof(MakeId), Name = "IX_Inventory_MakeId")]
public class Car : BaseEntity
{
  private string_color;
  [Required, StringLength(50)]
  public string Color
  {
    get => _color;
    set => _color = value;
  }
  [Required, StringLength(50)]
  public string PetName { get; set; }
  public int MakeId { get; set; }
  [ForeignKey(nameof(MakeId))]
  public Make MakeNavigation { get; set; }
  public Radio RadioNavigation { get; set; }
  [InverseProperty(nameof(Driver.Cards))]
  public IEnumerable<Driver> Drivers { get; set; }
}

This is the Fluent API equivalent of changing the table name:

modelBuilder.Entity<Car>(entity =>
{
  entity.ToTable("Inventory", "dbo");
});

Keys and Indices


To set the primary key for an entity, use the HasKey() method:

modelBuilder.Entity<Car>(entity =>
{
  entity.ToTable("Inventory","dbo");
  entity.HadKey(e=>e.Id);
});

This can be used to create a composite key too. The process is the same for creating indices except it uses the HasIndex() Fluent API method.

To make the index unique, use the IsUnique() method.

entity.HasIndex(e => e.MakeId, "IX_Inventory_MakeId").IsUnique();

Field Size and Nullability


Properties are configured by selecting them using the Property() method and then using additional methods to configure the property.

modelBuilder.Entity<Car>(entity =>
{
...
  entity.Property(e => e.Color)
    .IsRequired()
    .HasMaxLength(50);
  entity.Property(e => e.PetName)
    .IsRequired()
    .HasMaxLength(50);
});

Default Values


HasDefaultValue() can set the default value for a column. HasDefaultValueSql() can set the value to a database function.

RowVersion/Concurrency Tokens


SQL Server Sparse Columns


Computed Columns


Check Constraints


One-to-Many Relationships


To use the Fluent API to define one-to-many relationships, pick one of the entities to update. Both sides of the navigation chain are set in one block of code.

One-to-One Relationships


These are configured in the same way expect that WithOne() is used instead of WithMany().

Many-to-Many Relationships


Many-to-many relationships are much more customizable with the Fluent API. The foreign key field names, index names, and cascade behavior can all be set in the statements that define the relationship. It also allows for specifying the pivot table directly allowing for additional fields to be added and for simplified querying.

Excluding Entities from Migrations


Using IEntityTypeConfiguration Classes


Conventions, Annotations, and the Fluent API, Oh My!


 At this point in the chapter, you might be wondering which of the three options to use to shape your entities and their relationship to each other and the data store. The answer is all three. The conventions are always active (unless you override them with data annotations or the Fluent API). The data annotations can do almost everything the Fluent API methods can do and keep the information in the entity class themselves, which can increase code readability and support. The Fluent API is the most powerful of all three. Whether you use data annotations or the Fluent API, know that data annotations overrule the built-in conventions, and the methods of the Fluent API overrule everything.

Owned Entity Types

What is an effective tool that allows .NET programmers to work with relational data but is not necessarily good in developer efficiency?
What did Microsoft introduce since ADO.NET was not good enough in developer efficiency?
What are the strongly typed objects held in specialized LINQ aware collection classes operated on in Entity Framework called?
What data annotation in EF declares a property that is used as the foreign key for a navigation property?
What data annotation in EF declares a property as not nullable in the database?
What data annotation lets EF Core know which property is the backing field for a navigation property?
What data annotation informs EF Core of how entities are related by indicating the navigation property on the other end, and also makes the code more readable?
What data annotation in EF excludes a property or class in regard to database fields and tables?
What data annotation in EF declares the navigation property on the other end of a relationship?
In a one-to-many relationship in EF, the one side entity is the principal or dependent entity?
In a one-to-many relationship in EF, the many side entity is the principal or dependent entity?
What class is the ringleader component of EF Core?
What property of the DbContext class provides access to the database?
What class in EF Core holds all of the DbSet<T> properties?
What class in EF Core provides the SaveChanges() method that persists changes to the data store?
What member of DbContext saves all entity changes to the database (in a transaction) and returns the number of records affected?
What three members of DbContext can add, update, and remove entity instances, respectively, and also are usually called directly on the DbSet<T> properties?
What is the member of DbContext that provides access to information and operations for entity instances that the DbContext is tracking?
What is the state of an EF entity that is being tracked but does not yet exist in the database?
What is the state of an EF entity that is being tracked and is marked for deletion from the database?
What is the state of an EF entity that is not being tracked by the change tracker?
What is the state of an EF entity that is being tracked and has been changed?
What is the state of an EF entity that is being tracked, exists in the database, and has not been modified?
What is the recommended way (a type) to configure the DbContext instance at runtime?
What is the recommended way (a type) to configure the DbContext instance at design time?
What is the member of DbContext that is called when a model has been initialized, but before it has been finalized, and is where methods from the Fluent API are used to finalize the shape of the model?
What is the first thing or step to do in EF Core?
What method does the DbContext class expose that is used to shape your entities using the Fluent API?
What class is a specialized collection property used to interact with the database provider to read, add, update, and delete records in the database?
What interface does the DbSet<T> implement which enables the use of LINQ queries to retrieve records from the database?
What are the strongly typed classes that map to database tables called in EF?
How is the conceptual model of a physical database in Entity Framework (the entity data model) commonly referred to?
What are the two class to table mapping schemes available in EF Core?
What are, by definition, properties that map to a nonscalar type as defined by the database provider?
The Pro .NET book recommends ORMs for what type of operations?
The Pro .NET book recommends relying on the database for what type of operations?
What are the three types which are the most prominent main types in EF?
What type in EF manages the instance of ChangeTracker, exposes the virtual OnModelCreating() method, holds the DbSet<T> properties, and supplies the SaveChanges() method?
What member of DbContext has metadata about the shape of entities, the relationships between them, and how they map to the database (usually not used directly)?
What member of DbContext provides access to information and operations for entity instances that the specific DbContext is tracking?
LINQ queries against DbSet<T> properties in EF are translated into what?
What happens when the ChangeTracker.Clear() method is used in EF?
What approach when building a new app or adding EF Core into an existing application is when you create and configure your entity classes and the derived DbContext in code and then use migrations to update the database?
What approach when building a new app or adding EF Core into an existing application is when you scaffold the classes from an existing database?
What is the EF Core tooling that is a global CLI tool with the commands needed to scaffold existing databases into code, to create/remove database migrations, and to operate on a database?
What method, called when an EF model has been initialized, but not finalized yet, is where methods from the Fluent API are placed to finalize the shape of the model?
What did ADO.NET lack that made Microsoft introduce Entity Framework?
What does this line of code in a class derived from DbContext basically specify? public DbSet<Car> Cars { get; set; }
What in EF is a navigation property that maps to another entity (not a collection)?
Data retrieval queries in EF Core are created with LINQ queries written against properties of what type?
What in EF is a navigation property that maps to a collection of entities?
What in EF refers to DbSet<T> collections that are used to represent views, SQL statements, or tables without a primary key?
What method can you chain on to this to cause the database to be queried immediately? var cars = context.Cars.Where(x=>x.Color == "Yellow");
What do you need to do in between creating a record in code and calling SaveChanges() on the context in order to add the record to the database in EF?
Pro C# 10 with .NET 6 Chapter 22. Exploring Entity Framework Core Study cards
Creating Records

Records are added to the database by creating them in code, adding them to their DbSet<T>, and calling SaveChanges()/SaveChangesAsync() on the context. When SaveChanges() is executed, the ChangeTracker reports all the added entities, and EF Core (along with the database provider) creates the appropriate SQL statement(s) to insert the record(s).

Reminder: SaveChanges() executes in an implicit transaction, unless an explicit transaction is used.

Entity State

When an entity is created through code but not yet added to a DbSet<T>, the EntityState is Detached. Once a new entity is added to a DbSet<T>, the EntityState is set to Added. After SaveChanges() executes, the EntityState is set to Unchanged.

Add a Single Record Using Add

var newMake = new Make
{
  Name = "BMW"
};

context.Makes.Add(newMake);
context.SaveChanges();

All of the values passed into the SQL statement are parameterized to reduce the threat of scripting attacks.

Add a Single Record Using Attach

Add Multiple Records at Once

var cards = new List<Car>
{
  new() { Color = "Yellow" },
  new() { Color = "White" },
  new() { Color = "Pink" },
};

context.Cards.AddRange(cars);
context.SaveChanges();

The AddRange() method of a DbSet<T> property can be used to add multiple records in a single transaction.

Identity Column Considerations When Adding Records

Adding an Object Graph

Child records can be added to the database in the same call as the parent without specifically adding them into their own DbSet<T> by adding them to the collection navigation property of the parent entity.

var anotherMake = new Make { Name = "Honda" };
var car = new Car { Color = "Yellow" };
((List<Car>) anotherMake.Cars).Add(car);
context.Makes.Add(make);
context.SaveChanges();

Add Many-to-Many Records

Records can be added directly from one entity to the other without going through the pivot table.

Querying Data

Querying data using EF Core is typically accomplished using LINQ queries. New in EF Core 5, you can call ToQueryString() on most LINQ queries to examine that query that gets executed.

Get All Records

To get all the records for a table, simply use the DbSet<T> property directly without any LINQ statements. For immediate execution, add ToList() to the DbSet<T> property.

IQueryable<Car> cars = context.Cars;

List<Car> cars2 = context.Cars.ToList();

Filter Records

The Where() method is used to filter records from the DbSet<T>. Multiple Where() methods can be fluently chained to dynamically build the query.

IQueryable<Car> cars = context.Cars.Where(c=>c.Color == "Yellow");

IQueryable<Car> cars2 = context.Cars.Where(c => c.Color == "Yellow" && c.PetName == "Clunker");

Sort Records

The OrderBy() and OrderByDescending() methods set the sort(s) for the query in either ascending or descending order, respectively.

IOrderedQueryable<Car> cars = context.Cars.OrderBy(c=>c.Color);

Reverse Sort Records

The Reverse() method reverses the entire sort order.

Paging

Skip() skips the specified number of records while Take() retrieves the specified number of records.

Retrieve a Single Record

There are three main methods for returning a single record with a query: First()/FirstOrDefault(), Last()/LastOrDefault(), and Single()/SingleOrDefault(). All three return a single record.

First() returns the first record that matches and throws an exception if no record is found (EF).

FirstOrDefault() instead returns the default value for the type (null) if no record is found (EF).

Single() is like First() except it also throws an exception if more than one record matches the query (EF).

Last() is like First() but it returns that last record that matches.

Using First

When using the parameter less form of First() and FirstOrDefault(), the first record (based on database order or any preceding ordering clauses) will be returned.

var firstCar = context.Cars.First();

var firstCarByColor = context.Cars.OrderBy(c => c.Color).First();

try
{
  var firstCarNotFound = context.Cars.First(c => c.Id == 27);
}
catch (InvalidOperationException ex)
{
  Console.WriteLine(ex.Message);
}

Using Last

try
{
  context.Cars.Last();
}
catch (InvalidOperationException ex)
{
  Console.WriteLine(ex.Message);
}

Using Single

Using Find

Aggregation Methods

Any() and All()

Getting Data from Stored Procedures

Querying Related Data

Entity navigation properties are used to load an entity's related data. The related data can be loaded eagerly (one LINQ statement, one SQL query), eagerly with split queries (one LINQ statement, multiple SQL queries), explicitly (multiple LINQ calls, multiple SQL queries), or lazily (one LINQ statement, multiple on-demand SQL queries).

EF Core will automatically fix up entities as they are loaded into the Change Tracker. If all Make records are loaded into the DbSet<Make> collection property (example) and all Car records are loaded into DbSet<Car>, then they will be accessible to each other through navigation properties.

Eager Loading

Filtered Include

Eager Loading with Split Queries

Many-to-Many Queries

You can write the following LINQ statement to get the Car and related Driver records:

var carsAndDrivers = context.Cars.Include(x => x.Drivers).Where(x=>x.Drivers.Any());

Explicit Loading

Lazy Loading

Updating Records

Records are updated by loading them into DbSet<T> as a tracked entity, changing them through code, and then calling SaveChanges(). When SaveChanges() is executed, the ChangeTracker reports all of the modified entities, and EF Core (along with the database provider) creates the appropriate SQL statement(s).

Entity State

When a tracked entity is edited, EntityState is set to Modified. After the changes are successfully saved, the state is returned to Unchanged.

Update Tracked Entities

Updating a single record is much like adding a single record, except that the initial record is retrieved from the database and not created through code. Load the record from the database into a tracked entity, make some changes, and then call SaveChanges().

var car = context.Cars.First();
car.Color = "Green";
context.SaveChanges();

Update Nontracked Entities

EF Core must be notified that the entity should exist in the database and needs to be updated.

There are two ways, and either way, SaveChanges() must be called for the values to persist.

context.Cars.Update(updatedCar);

context.Entry(updatedCar).State = EntityState.Modified;

Deleting Records

One or more entities are marked for deletion by calling Remove() (for a single entity) or RemoveRange() (for a list of entities) on the appropriate DbSet<T> property or by setting the state for the entity/entities to Deleted. The removal process will cause cascade effects on navigation properties based on the rules configured in OnModelCreating() (or by EF Core conventions).

Entity State
What is the EntityState of an entity that has been created through code but has not yet been added to a DbSet<T>?
What method (when called) corresponds with ChangeTracker reporting all of the added entities and EF Core creating the appropriate SQL statements?
What is the EntityState of an entity after SaveChanges() executes?
What is the method of a DbSet<T> property that adds a single record?
What adding an object graph by adding child records into the parent's collection navigation property, does EF Core automatically retrieve the parent record's primary key identifier to include in the Insert statement for the foreign key id of the child record?
What is the method of a DbSet<T> property that adds multiple records?
What method can be called on most LINQ queries being used in EF Core to examine the query that gets executed?
What method is used to filter records from a DbSet<T>?
When you add child records to the database by putting them in the collection navigation property of their parent (EF) what is a cool term for what you are adding to the database?
What method can you call on most LINQ queries to examine the actual query that gets executed against the database (new in EF Core 5)?
What method is used to filter records from a DbSet<T> in EF Core?
What term refers to loading related records from multiple tables in one database call?
Which of the two methods that provide paging capabilities in EF Core skips the specified number of records?
Which of the two methods that provide paging capabilities in EF Core retrieves the specified number of records?
Pro C# 10 with .NET 6 Chapter 23. Building a Data Access Layer with Entity Framework Core
Pro C# 10 with .NET 6 Chapter 30 Introducing ASP.NET Core Study cards

Introducing ASP.NET Core

The three last applications explained by the Pro C# with .NET 6 book are what types of apps?
What web server could ASP.NET Core applications use after the dependency on System.Web was removed in the rewrite of ASP.NET?
What encompasses ASP.NET MVC, ASP.NET Web API, and Razor Pages in a single development framework?
What command can be used instead of dotnet run in ASP.NET Core development to run with Hot Reload enabled?
What is the base class of Controller in ASP.NET Core?
What are methods on an ASP.NET controller that return an IActionResult (or Task<IActionResult> for async operations) or a class that implements IActionResult?
What is the ASP.NET Core type that a controller action returns?
What approach to preventing cross-site request forgery attacks does ASP.NET Core use which creates a unique and unpredictable server side token that is sent to the browser and must come back in any request from the browser or the request is refused?
What attribute can be added to an HTTP Post method in an ASP.NET Core application to opt in for the STP token validation (this is enabled by default in Razor Page Web Apps)?
By convention, where are ASP.NET Core controllers placed in the directory structure?
What is the web server typically used to run ASP.NET Core apps that can also act as a reverse proxy to use IIS, Apache, Nginx, etc.?
What is the command to run an ASP.NET Core app with "Hot Reload" enabled?
With the unification of ASP.NET Core (combining ASP.NET MVC5 and ASP.NET Web API), the Controller, ApiController, and AsyncController base classes have been combined into one class, Controller, which has what base class?
ASP.NET Core is developed as a modular system of what?
What folder is where the views are placed in an ASP.NET Core (MVC style) application?
What special folder for views in an ASP.NET Core app is accessible to all controllers and their action methods?
What would be the views folder specifically for the views used by the HomeController class in ASP.NET Core?
What is the folder where pages for the application are stored when building web applications using Razor pages?
What special folder under Pages in a Razor page based web application is accessible to all pages?
What feature can be used to organize related functionality into a group as a separate namespace for routing and folder structure for views and Razor pages where each gets its own set of controllers (API apps), controllers and views (MVC style), and pages (Razor page based apps)?
What parent folder stores the areas in ASP.NET Core?
What is the folder in ASP.NET Core web applications that the client side files are placed in?
What feature refers to how ASP.NET Core matches HTTP requests to the proper executable endpoints to handle those requests, and also create URLs from executable endpoints?
What is the C# attribute used in attribute routing in ASP.NET Core?
What type in ASP.NET Core is involved in model binding and contains an entry for every property being bound and an entry for the model itself?
What feature of ASP.NET Core is a process where the name-value pairs submitted in an HTTP Post call are used to assign values to models?
What is the ordered collection that holds URL patterns with variable placeholders (tokens) and optional literals that are the route definitions in an ASP.NET Core app?
What is it called when routes in an ASP.NET Core app are configured using C# attributes on controllers and their action methods?
What are the optional placeholders in the route table's URL patterns called in ASP.NET Core?
What is the difference between a double ** and a single * in a route definition like car/{**slug} (ASP.NET Core)?
What is a restriction on defining routes using tokens in ASP.NET Core?
What is the process where ASP.NET Core uses the name-value pairs submitted in an HTTP Post call to assign values to models?
What are the three reserved route tokens for ASP.NET MVC and RESTful service apps?
Pro C# 10 with .NET 6 Chapter 31 Diving Into ASP.NET Core Study cards
An instance of what type can be used to access environment variables and file locations in an ASP.NET Core app?
What extension method of the HostEnvironmentEnvExtensions class returns true if the environment variable is set to Production (ASP.NET Core)?
What type is used to create an instance of ILogger<T> in ASP.NET Core?
What extension method of the HostEnvironmentEnvExtensions class returns true if the environment variable is set to Development (ASP.NET Core)?
What are .NET console applications that create and configure a WebApplication (an instance of IHost)?
What is the type that you call CreateBuilder on in a typical ASP.NET Core Program.cs?
What class in an ASP.NET Core app implements the IHostEnvironment interface and includes environment variables and file locations?
What property of the IWebHostEnvironment in an ASP.NET Core app is set to the value of the ASPNETCORE_ENVIRONMENT environment variable?
What is the class in an ASP.NET Core app which has a property called EnvironmentName, usually with the value of ASPNETCORE_ENVIRONMENT?
What environment variable sets the value of the EnvironmentName property of IWebHostEnvironment?
What type in an ASP.NET Core app is used to determine the runtime environment?
What file usually sets the ASPNETCORE_ENVIRONMENT environment variable when developing the app?
What static class in ASP.NET Core supplies three environment names for you to use?
What class provides extension methods (isProduction(), isStaging(), etc.) on the IHostEnvironment for working with the EnvironmentName property?
ASP.NET Core apps are .NET console apps that create and configure a what?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //more code to be placed here later } app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); What adds in support for using controllers and action methods?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //more code to be placed here later } app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); What creates the basic OpenAPI support?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //more code to be placed here later } app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); What compacts the most typical application setup into one method call (it configures the app using environment variables and JSON files, configures the default logging provider, and sets up the dependency injection container)?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //more code to be placed here later } app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); What type is used here to register services and do additional configuration after CreateBuilder() is called?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { //more code to be placed here later } app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); What starts the app and gets everything ready to receive web requests and respond to them?
What would you use instead of AddControllers() (used for a RESTful service) in an MVC style ASP.NET Core app?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); What turns on HTTP Strict Transport Security?
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); What enables static content (images, JavaScript files, CSS files, etc.) to be rendered through the application?
What mechanism that supports loose coupling between objects was one of the main tenets in the rewrite of ASP.NET Core?
What are the three lifetime options that can be used when an item is configured into the ASP.NET Core dependency injection container?
What ASP.NET Core DI container lifetime option is "created each time they are needed"?
What ASP.NET Core DI container lifetime option is "created once for each request"?
What ASP.NET Core DI container lifetime option is "created once on first request and then reused for the lifetime of the object"?
What ASP.NET Core DI container lifetime option is recommended for Entity Framework DbContext objects?
What type are services added into the DI container through (ASP.NET Core)?
What line is it important that you add services to the ASP.NET Core DI container before?
What method adds in the necessary services to support the MVC pattern in ASP.NET Core?
What do RESTful service web applications use instead of the AddControllersWithViews() method since they don't use views but do need controller support?
What method that adds the DbContext into the DI container creates a pool of instances that are cleaned between requests (ensuring no data contamination)?
What attribute must be used in action methods to distinguish between a binding target and a service from the DI container?
What class did ASP.NET Core 2.1 introduce that creates and configures HttpClient instances?
What are the options for web servers when deploying an ASP.NET Core app to Linux and not in a container?
What does the Pro C# book call an example of a popular container-based deployment model?
What interface is logging in ASP.NET Core based on?
What is the logging framework that can be used in ASP.NET Core that the Pro C# book covers?
Pro C# 10 with .NET 6 Chapter 32 RESTful Services with ASP.NET Core Study cards
What unified ASP.NET Web API and MVC into one framework?
From the beginning, ASP.NET Web API had been designed to be a service-based framework for building what kind of services?
How does the Pro C# book say JSON is pronounced?
What are requests that originate from one server to the API of another server?
What are requests that originate from another server communicating with an API?
What is short for cross-origin requests?
What method must be called before adding the CORS policy to the services collection in an ASP.NET Core app?
What does the Pro C# book define as "URI that points to a physical resource on a network?"
What do web APIs use to communicate success or failure (HTTP)?
What attribute provides REST-specific rules, conventions, and behaviors when combined with the ControllerBase class?
What status code will be returned by an ASP.NET Core controller if there is an issue with model binding?
What technique for web API versioning would leave 1.0 action methods in a ValuesController and create a Values2Controller to hold the version 2.0 methods?
What are the two open source libraries the Pro C# book mentions add Swagger into ASP.NET Core APIs?
What is the file that Swashbuckle generates that contains information for the site, each endpoint, and any objects involved in the endpoints?
What is the interactive UI that Swashbuckle provides to present the contents of swagger.json?
What is the syntax for method signature comments that .NET can generate an XML documentation file?
What does the Pro C# book call concatenating a username and password with a colon, Base64 encoding it, and putting this in the Authorization header of the request?
What attribute can be used in ASP.NET Core at a controller or action to require a user to be authenticated in order to access the resource?
What attribute can be used in ASP.NET Core at a controller or action to turn off protection for a resource?
Pro C# 10 with .NET 6 Private Study cards
These notes should be moved to Pro C# book (I accidentally put them on the homepage)
What is the first part in the four-part numerical version numbers of .NET assemblies?
What is the second part in the four-part numerical version numbers of .NET assemblies?
What is the third part in the four-part numerical version numbers of .NET assemblies?
What is the fourth part in the four-part numerical version numbers of .NET assemblies?
What does the Pro C# 10 book call these of a type: member names, implemented interfaces, base classes, and constructors?
What part of a .NET assembly makes it self-describing?
What is the blob of metadata that describes a .NET assembly and is part of it?
What is the command to use dumpbin.exe to look at an assembly's operating system header info?
What part of a .NET assembly establishes the fact that the assembly can be loaded and manipulated by the target operating system?
What example does the Pro C# book say is when you would become interested in the header data embedded in a .NET assembly?
What data that is part of a .NET assembly is used by the runtime as the image data loads into memory?
What is another way to refer to the manifest associated to a .NET assembly?
What does .NET support that contain nothing but localized resources like if you wanted to partition resources based on culture to build international software?
What are .NET programs that have a single-entry point, can interact with the console, and can be launched directly from the operating system?
What is the .NET Application Host that launches console applications in .NET (different from .NET Framework)?
What are the two cases of what the single-entry point can be in a .NET console app?
What type of .NET programs do not have an entry point and therefore cannot be launched directly?
What was the class library project introduced with .NET Core 1.0 that can be referenced by both .NET Framework and .NET applications?
What are .NET assemblies that are used to encapsulate logic, custom types, and are referenced by other class libraries and/or console apps?
What are like classes that can contain only static methods in Visual Basic?
What in Visual Basic is equivalent to a C# static class?
What is the default mechanism for loading .NET and its related framework pieces (ASP.NET Core, EF Core, etc.)?
What node do you add to a .NET *.csproj file to cause the package to be rebuilt every time the software is built, either in bin/Debug or bin/Release?
What is the XML-based file that controls the location of NuGet packages (on Windows)?
What directory is NuGet.Config located in on Windows?
What is the largest NuGet package repository in the world?
What is the dotnet CLI command to package up a NuGet package after running dotnet build -c Release?
How do many organizations package their standard .NET assemblies for stuff like logging and error reporting for consumption into their line-of-business applications?
What keyword in Visual Basic declares a local variable?
What is the statement in a Visual Basic program (Program.vb) that would be equivalent to using ExampleLibrary; in C#?
What keyword needs to be used to declare types in .NET if other .NET apps are to use them as well?
What does a .NET assembly contain instead of platform-specific instructions?
The just-in-time compiler that compiles CIL code on the fly does so according to instructions that are specific to what?
What short option can you add to any command in the .NET CLI to use the help system which is pretty good?
Can you live a happy and productive life without understanding the details of the CIL programming language?
What type of code does a .NET assembly contain that is a platform- and CPU-agnostic intermediate language?
What header that is part of a .NET assembly must be there for it to be hosted by the .NET runtime?
What is the command using dumpbin.exe to see the CLR header of an assembly?
What part of a .NET assembly enables the runtime to understand the layout of the managed file?
What will you be blissfully ignorant of but should be aware is used under the covers when the operating system loads a .NET assembly into memory?
What utility does the Pro C#10 book recommend that ships with the C++ profiling tools?
What first two things in the format of a .NET assembly can you pretty much always ignore?
What specific thing in the manifest of a .NET assembly makes it self-describing?
What does the .NET runtime not need to do to resolve its location given how self-documented assemblies are?
Under default settings, what version is a .NET assembly assigned given the default .NET project settings?
What further establishes a type's identity in C# compared to namespaces?