Welcome to the most comprehensive foundational guide available on the topic of C# coding and .NET. This book goes beyond “do this, to achieve this” to drill down into the core stuff that makes a good developer, great. This expanded 11th edition delivers loads of new content on Entity Framework, Razor Pages, Web APIs and more. You will find the latest C# 10 and .NET 6 features served up with plenty of “behind the curtain” discussion designed to expand developers’ critical thinking skills when it comes to their craft. Coverage of ASP.NET Core, Entity Framework Core, and more sits alongside the latest updates to the new unified .NET platform, from performance improvements to Windows Desktop apps on .NET 6, updates in XAML tooling, and expanded coverage of data files and data handling. Going beyond the latest features in C# 10, all code samples are rewritten for this latest release. Dive in and discover why this essential classic is a favorite of C# developers worldwide. Gain a solid foundation in object-oriented development techniques, attributes and reflection, generics and collections, and numerous advanced topics not found in other texts (such as CIL opcodes and emitting dynamic assemblies). Pro C# 10 with .NET 6 will build your coding confidence putting C# into practice, and exploring the .NET universe and its vast potential on your own terms. What You Will Learn Explore C# 10 features and updates in records and record structs, global and implicit using directives, file level namespaces, extended property patterns, and more Develop applications with C# and modern frameworks for services, web, and smart client applications Hit the ground running with ASP.NET Core web applications using MVC and Razor Pages, including view components, custom tag helpers, custom validation, GDPR support, and areas Build ASP.NET RESTful services complete with versioning, enhanced swagger, and basic authentication Embrace Entity Framework Core for building real-world, data-centric applications, with deeply expanded coverage new to this edition including SQL Server temporal table support Dive into Windows Desktop Apps on .NET 6 using Windows Presentation Foundation Understand the philosophy behind .NET Discover the new features in .NET 6, including single file applications, smaller container images, and more Who This Book Is For Developers of any level who want to either learn C# and .NET or want to take their skills to the next level. “Amazing! Provides easy-to-follow explanations and examples. I remember reading the first version of this book; this is a ‘must-have’ for your collection if you are learning .NET!” – Rick McGuire, Senior Application Development Manager, Microsoft “Phil is a journeyman programmer who brings years of experience and a passion for teaching to make this fully revised and modernized ‘classic’ a ‘must-have’. Any developer who wants full-spectrum, up-to-date coverage of both the C# language and how to use it with .NET and ASP.NET Core should get this book.” – Brian A. Randell, Partner, MCW Technologies and Microsoft MVP Table of Contents About the Authors About the Technical Reviewers Acknowledgments Introduction Part I: Introducing C# and .NET 6 Chapter 1: Introducing C# and .NET 6 Exploring Some Key Benefits of the .NET Platform Understanding the .NET Support Lifecycle Previewing the Building Blocks of the .NET Platform The Role of the Base Class Libraries The Role of .NET Standard What C# Brings to the Table Major Features in Prior Releases New Features in C# 10 Managed vs. Unmanaged Code Using Additional .NET–Aware Programming Languages Getting an Overview of .NET Assemblies The Role of the Common Intermediate Language Benefits of CIL Compiling CIL to Platform-Specific Instructions Precompiling CIL to Platform-Specific Instructions The Role of .NET Type Metadata The Role of the Assembly Manifest Understanding the Common Type System CTS Class Types CTS Interface Types CTS Structure Types CTS Enumeration Types CTS Delegate Types CTS Type Members Intrinsic CTS Data Types Understanding the Common Language Specification Ensuring CLS Compliance Understanding the .NET Runtime Distinguishing Between Assembly, Namespace, and Type Accessing a Namespace Programmatically Global Using Statements (New 10.0) Implicit Global Using Statements (New 10.0) File Scoped Namespaces (New 10.0) Referencing External Assemblies Exploring an Assembly Using ildasm.exe Summary Chapter 2: Building C# Applications Installing .NET 6 Understanding the .NET Version Numbering Scheme Confirming the .NET 6 Install Checking For Updates Use an Earlier Version of the .NET (Core) SDK Building .NET Core Applications with Visual Studio Installing Visual Studio 2022 (Windows) Taking Visual Studio 2022 for a Test-Drive Using the New Project Dialog and C# Code Editor Changing the Target .NET Core Framework Using C# 10 Features Running and Debugging Your Project Using Solution Explorer Using the Visual Class Diagram Tool Building .NET Core Applications with Visual Studio Code Taking Visual Studio Code for a Test-Drive Creating Solutions and Projects Exploring the Visual Studio Code Workspace Restoring Packages, Building and Running Programs Debugging Your Project Finding the .NET Core and C# Documentation Summary Part II: Core C# Programming Chapter 3: Core C# Programming Constructs, Part 1 Breaking Down a Simple C# Program (Updated C# 10) Using Variations of the Main() Method (Updated 7.1) Using Top-Level Statements (New 9.0) Specifying an Application Error Code (Updated 9.0) Processing Command-Line Arguments (Updated 9.0) Specifying Command-Line Arguments with Visual Studio 2022 Additional Members of the System.Environment Class (Updated 10.0) Using the System.Console Class Performing Basic Input and Output (I/O) with the Console Class Formatting Console Output Formatting Numerical Data Formatting Numerical Data Beyond Console Applications Working with System Data Types and Corresponding C# Keywords Understanding Variable Declaration and Initialization The default Literal (New 7.1) Using Intrinsic Data Types and the new Operator (Updated 9.0) Understanding the Data Type Class Hierarchy Understanding the Members of Numerical Data Types Understanding the Members of System.Boolean Understanding the Members of System.Char Parsing Values from String Data Using TryParse to Parse Values from String Data Using System.DateTime and System.TimeSpan (Updated 10.0) Working with the System.Numerics Namespace Using Digit Separators (New 7.0) Using Binary Literals (New 7.0/7.2) Working with String Data Performing Basic String Manipulation Performing String Concatenation Using Escape Characters Performing String Interpolation Performance Improvements (Updated 10.0) Defining Verbatim Strings (Updated 8.0) Working with Strings and Equality Modifying String Comparison Behavior Strings Are Immutable Using the System.Text.StringBuilder Type Narrowing and Widening Data Type Conversions Using the checked Keyword Setting Project-wide Overflow Checking (Project File) Setting Project-wide Overflow Checking (Visual Studio) Selecting the Build Configuration Using the unchecked Keyword Understanding Implicitly Typed Local Variables Declaring Numerics Implicitly Understanding Restrictions on Implicitly Typed Variables Implicit Typed Data Is Strongly Typed Data Understanding the Usefulness of Implicitly Typed Local Variables Working with C# Iteration Constructs Using the for Loop Using the foreach Loop Using Implicit Typing Within foreach Constructs Using the while and do/while Looping Constructs A Quick Discussion About Scope Working with Decision Constructs and the Relational/Equality Operators Using the if/else Statement Using Equality and Relational Operators Using if/else with Pattern Matching (New 7.0) Making Pattern Matching Improvements (New 9.0) Using the Conditional Operator (Updated 7.2, 9.0) Using Logical Operators Using the switch Statement Performing switch Statement Pattern Matching (New 7.0, Updated 9.0) Using switch Expressions (New 8.0) Summary Chapter 4: Core C# Programming Constructs, Part 2 Understanding C# Arrays Looking at the C# Array Initialization Syntax Understanding Implicitly Typed Local Arrays Defining an Array of Objects Working with Multidimensional Arrays Using Arrays As Arguments or Return Values Using the System.Array Base Class Using Indices and Ranges (New 8.0, Updated 10.0) Understanding Methods Understanding Expression-Bodied Members Understanding Local Functions (New 7.0, Updated 9.0) Understanding Static Local Functions (New 8.0) Understanding Method Parameters Understanding Method Parameter Modifiers Understanding the Default Parameter-Passing Behavior The Default Behavior for Value Types The Default Behavior for Reference Types Using the out Modifier (Updated 7.0) Discarding out Parameters (New 7.0) The out Modifier in Constructors and Initializers (New 7.3) Using the ref Modifier Using the in Modifier (New 7.2) Using the params Modifier Defining Optional Parameters Using Named Arguments (Updated 7.2) Understanding Method Overloading Checking Parameters for Null (Updated 10.0) Understanding the enum Type Controlling the Underlying Storage for an enum Declaring enum Variables Using the System.Enum Type Dynamically Discovering an enum’s Name-Value Pairs Using Enums, Flags, and Bitwise Operations Understanding the Structure Creating Structure Variables Structure Constructors (Updated 10.0) Using Field Initializers (New 10.0) Using Read-Only Structs (New 7.2) Using Read-Only Members (New 8.0) Using ref Structs (New 7.2) Using Disposable ref Structs (New 8.0) Understanding Value Types and Reference Types Using Value Types, Reference Types, and the Assignment Operator Using Value Types Containing Reference Types Passing Reference Types by Value Passing Reference Types by Reference Final Details Regarding Value Types and Reference Types Understanding C# Nullable Types Using Nullable Value Types Using Nullable Reference Types (New 8.0, Updated 10.0) Opting in for Nullable Reference Types (Updated 10.0) Nullable Reference Types in Action Migration Considerations Change Nullable Warnings to Errors Operating on Nullable Types The Null-Coalescing Operator The Null-Coalescing Assignment Operator (New 8.0) The Null Conditional Operator Understanding Tuples (New/Updated 7.0) Getting Started with Tuples Using Inferred Variable Names (Updated 7.1) Understanding Tuple Equality/Inequality (New 7.3) Understanding Tuples as Method Return Values Understanding Discards with Tuples Understanding Tuple Pattern Matching switch Expressions (New 8.0) Deconstructing Tuples (Updated 10.0) Deconstructing Tuples with Positional Pattern Matching (New 8.0) Summary Part III: Object Oriented Programming with C# Chapter 5: Understanding Encapsulation Introducing the C# Class Type Allocating Objects with the new Keyword Understanding Constructors Understanding the Role of the Default Constructor Defining Custom Constructors Constructors As Expression-Bodied Members (New 7.0) Constructors with out Parameters (New 7.3) Understanding the Default Constructor Revisited Understanding the Role of the this Keyword Chaining Constructor Calls Using this Observing Constructor Flow Revisiting Optional Arguments Understanding the static Keyword 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 Understanding the Role of Encapsulation Understanding the Role of Inheritance Understanding the Role of Polymorphism Understanding C# Access Modifiers (Updated 7.2) Using the Default Access Modifiers Using Access Modifiers and Nested Types Understanding the First Pillar: C#’s Encapsulation Services Encapsulation Using Traditional Accessors and Mutators Encapsulation Using Properties Properties As Expression-Bodied Members (New 7.0) Using Properties Within a Class Definition Read-Only Properties Write-Only Properties Mixing Private and Public Get/Set Methods on Properties Revisiting the static Keyword: Defining Static Properties Pattern Matching with Property Patterns (New 8.0) Extended Property Patterns (New 10.0) Understanding Automatic Properties Interacting with Automatic Properties Automatic Properties and Default Values Initializing Automatic Properties Understanding Object Initialization Looking at the Object Initialization Syntax Using init-Only Setters (New 9.0) Calling Custom Constructors with Initialization Syntax Initializing Data with Initialization Syntax Working with Constant and Read-Only Field Data Understanding Constant Field Data Constant Interpolated Strings (New 10.0) Understanding Read-Only Fields Understanding Static Read-Only Fields Understanding Partial Classes Records (New 9.0) Immutable Record Types with Standard Property Syntax Immutable Record Types with Positional Syntax Deconstructing Mutable Record Types Mutable Record Types Value Equality with Record Types Copying Record Types Using with Expressions Record Structs (New 10.0) Mutable Record Structs Immutable Record Structs Deconstructing Record Structs Summary Chapter 6: Understanding Inheritance and Polymorphism Understanding the Basic Mechanics of Inheritance Specifying the Parent Class of an Existing Class Regarding Multiple Base Classes Using the sealed Keyword Revisiting Visual Studio Class Diagrams Understanding the Second Pillar of OOP: The Details of Inheritance Calling Base Class Constructors with the base Keyword Keeping Family Secrets: The protected Keyword Adding a sealed Class Understanding Inheritance with Record Types (New 9.0) 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 Understanding Nested Type Definitions Understanding the Third Pillar of OOP: C#’s Polymorphic Support Using the virtual and override Keywords Overriding Virtual Members with Visual Studio/Visual Studio Code Sealing Virtual Members (Updated 10.0) Understanding Abstract Classes Understanding the Polymorphic Interface Understanding Member Shadowing Understanding Base Class/Derived Class Casting Rules Using the C# as Keyword Using the C# is Keyword (Updated 7.0, 9.0) Discards with the is Keyword (New 7.0) Revisiting Pattern Matching (New 7.0) Discards with switch Statements (New 7.0) Understanding the Super Parent Class: System.Object Overriding System.Object.ToString() Overriding System.Object.Equals() Overriding System.Object.GetHashCode() Testing Your Modified Person Class Using the Static Members of System.Object Summary Chapter 7: Understanding Structured Exception Handling Ode to Errors, Bugs, and Exceptions The Role of .NET Exception Handling The Building Blocks of .NET Exception Handling The System.Exception Base Class The Simplest Possible Example Throwing a General Exception Catching Exceptions Throw As Expression (New 7.0) Configuring the State of an Exception The TargetSite Property The StackTrace Property The HelpLink Property The Data Property System-Level Exceptions (System.SystemException) Application-Level Exceptions (System.ApplicationException) Building Custom Exceptions, Take 1 Building Custom Exceptions, Take 2 Building Custom Exceptions, Take 3 Processing Multiple Exceptions General catch Statements Rethrowing Exceptions Inner Exceptions The finally Block Exception Filters Debugging Unhandled Exceptions Using Visual Studio Summary Chapter 8: Working with Interfaces Understanding Interface Types Interface Types vs. Abstract Base Classes Defining Custom Interfaces Implementing an Interface Invoking Interface Members at the Object Level Obtaining Interface References: The as Keyword Obtaining Interface References: The is Keyword (Updated 7.0) Default Implementations (New 8.0) Static Constructors and Members (New 8.0) Interfaces as Parameters Interfaces as Return Values Arrays of Interface Types Implementing Interfaces Using Visual Studio or Visual Studio Code Explicit Interface Implementation Designing Interface Hierarchies Interface Hierarchies with Default Implementations (New 8.0) Multiple Inheritance with Interface Types The IEnumerable and IEnumerator Interfaces Building Iterator Methods with the yield Keyword Guard Clauses with Local Functions (New 7.0) Building a Named Iterator The ICloneable Interface A More Elaborate Cloning Example The IComparable Interface Specifying Multiple Sort Orders with IComparer Custom Properties and Custom Sort Types Summary Chapter 9: Understanding Object Lifetime Classes, Objects, and References The Basics of Object Lifetime The CIL of new Setting Object References to null Determining If an Object Is Live Understanding Object Generations Ephemeral Generations and Segments Garbage Collection Types Background Garbage Collection The System.GC Type Forcing a Garbage Collection Building Finalizable Objects Overriding System.Object.Finalize() Detailing the Finalization Process Building Disposable Objects Reusing the C# using Keyword Using Declarations (New 8.0) Building Finalizable and Disposable Types A Formalized Disposal Pattern Understanding Lazy Object Instantiation Customizing the Creation of the Lazy Data Part IV: Advanced C# Programming Chapter 10: Collections and Generics The Motivation for Collection Classes The System.Collections Namespace An Illustrative Example: Working with the ArrayList A Survey of System.Collections.Specialized Namespace The Problems of Nongeneric Collections The Issue of Performance The Issue of Type Safety A First Look at Generic CollectionsT The Role of Generic Type Parameters Specifying Type Parameters for Generic Classes/Structures Specifying Type Parameters for Generic Members Specifying Type Parameters for Generic Interfaces The System.Collections.Generic Namespace Understanding Collection Initialization Syntax Working with the List Class Working with the Stack Class Working with the Queue Class Working with the PriorityQueue Class (New 10) Working with the SortedSet Class Working with the Dictionary Class The System.Collections.ObjectModel Namespace Working with ObservableCollection Creating Custom Generic Methods Inference of Type Parameters Creating Custom Generic Structures and Classes Default Value Expressions with Generics Default Literal Expressions (New 7.1) Pattern Matching with Generics (New 7.1) Constraining Type Parameters Examples of Using the where Keyword The Lack of Operator Constraints Summary Chapter 11: Advanced C# Language Features Understanding Indexer Methods Indexing Data Using String Values Overloading Indexer Methods Indexers with Multiple Dimensions Indexer Definitions on Interface Types Understanding Operator Overloading Overloading Binary Operators What of the += and –= Operators? Overloading Unary Operators Overloading Equality Operators Overloading Comparison Operators Final Thoughts Regarding Operator Overloading Understanding Custom Type Conversions Recall: Numerical Conversions Recall: Conversions Among Related Class Types Creating Custom Conversion Routines Additional Explicit Conversions for the Square Type Defining Implicit Conversion Routines Understanding Extension Methods Defining Extension Methods Invoking Extension Methods Importing Extension Methods Extending Types Implementing Specific Interfaces Extension Method GetEnumerator Support (New 9.0) Understanding Anonymous Types Defining an Anonymous Type The Internal Representation of Anonymous Types The Implementation of ToString() and GetHashCode() The Semantics of Equality for Anonymous Types Anonymous Types Containing Anonymous Types Working with Pointer Types The unsafe Keyword Working with the * and & Operators An Unsafe (and Safe) Swap Function Field Access via Pointers (the -> Operator) The stackalloc Keyword Pinning a Type via the fixed Keyword The sizeof Keyword Summary Chapter 12: Delegates, Events, and Lambda Expressions Understanding the Delegate Type Defining a Delegate Type in C# The System.MulticastDelegate and System.Delegate Base Classes The Simplest Possible Delegate Example Investigating a Delegate Object Sending Object State Notifications Using Delegates Enabling Multicasting Removing Targets from a Delegate’s Invocation List Method Group Conversion Syntax Understanding Generic Delegates The Generic Action and Func Delegates Understanding C# Events The C# event Keyword Events Under the Hood Listening to Incoming Events Simplifying Event Registration Using Visual Studio Creating Custom Event Arguments The Generic EventHandler Delegate Understanding C# Anonymous Methods Accessing Local Variables Using static with Anonymous Methods (New 9.0) Discards with Anonymous Methods (New 9.0) Understanding Lambda Expressions Dissecting a Lambda Expression Processing Arguments Within Multiple Statements Lambda Expressions with Multiple (or Zero) Parameters Using static with Lambda Expressions (New 9.0) Discards with Lambda Expressions (New 9.0) Retrofitting the CarEvents Example Using Lambda Expressions Lambdas and Expression-Bodied Members (Updated 7.0) Summary Chapter 13: LINQ to Objects LINQ-Specific Programming Constructs Implicit Typing of Local Variables Object and Collection Initialization Syntax Lambda Expressions Extension Methods Anonymous Types Understanding the Role of LINQ LINQ Expressions Are Strongly Typed The Core LINQ Assemblies Applying LINQ Queries to Primitive Arrays Once Again, Using Extension Methods Once Again, Without LINQ Reflecting Over a LINQ Result Set LINQ and Implicitly Typed Local Variables LINQ and Extension Methods The Role of Deferred Execution DefaultIfEmpty (New 10.0) The Role of Immediate Execution Set Default for [First/Last/Single]OrDefault Methods (New 10) Returning the Result of a LINQ Query Returning LINQ Results via Immediate Execution Applying LINQ Queries to Collection Objects Accessing Contained Subobjects Applying LINQ Queries to Nongeneric Collections Filtering Data Using OfType () Investigating the C# LINQ Query Operators Basic Selection Syntax Obtaining Subsets of Data Paging Data Paging Data with Ranges (New 10.0) Paging Data with Chunks (New 10.0) Projecting New Data Types Projecting to Different Data Types Obtaining Counts Using Enumerable Obtaining Nonenumerated Counts (New 10.0) Reversing Result Sets Sorting Expressions LINQ As a Better Venn Diagramming Tool Venn Diagramming with Selectors (New 10.0) Removing Duplicates Removing Duplicates with Selectors (New 10.0) LINQ Aggregation Operations Aggregation with Selectors (New 10.0) The Internal Representation of LINQ Query Statements Building Query Expressions with Query Operators (Revisited) Building Query Expressions Using the Enumerable Type and Lambda Expressions Building Query Expressions Using the Enumerable Type and Anonymous Methods Building Query Expressions Using the Enumerable Type and Raw Delegates Summary Chapter 14: Processes, AppDomains, and Load Contexts The Role of a Windows Process The Role of Threads Interacting with Processes Using .NET Core Enumerating Running Processes Investigating a Specific Process Investigating a Process’s Thread Set Investigating a Process’s Module Set Starting and Stopping Processes Programmatically Controlling Process Startup Using the ProcessStartInfo Class Leveraging OS Verbs with ProcessStartInfo Understanding .NET Application Domains The System.AppDomain Class Interacting with the Default Application Domain Enumerating Loaded Assemblies Assembly Isolation with Application Load Contexts Summarizing Processes, AppDomains, and Load Contexts Summary Chapter 15: Multithreaded, Parallel, and Async Programming The Process/AppDomain/Context/Thread Relationship The Problem of Concurrency The Role of Thread Synchronization The System.Threading Namespace The System.Threading.Thread Class Obtaining Statistics About the Current Thread of Execution The Name Property The Priority Property Manually Creating Secondary Threads Working with the ThreadStart Delegate Working with the ParameterizedThreadStart Delegate The AutoResetEvent Class Foreground Threads and Background Threads The Issue of Concurrency Synchronization Using the C# lock Keyword Synchronization Using the System.Threading.Monitor Type Synchronization Using the System.Threading.Interlocked Type Programming with Timer Callbacks Using a Stand-Alone Discard (New 7.0) Understanding the ThreadPool Parallel Programming Using the Task Parallel Library The System.Threading.Tasks Namespace The Role of the Parallel Class Data Parallelism with the Parallel Class Accessing UI Elements on Secondary Threads The Task Class Handling Cancellation Request Task Parallelism Using the Parallel Class Parallel LINQ Queries (PLINQ) Opting in to a PLINQ Query Cancelling a PLINQ Query Async Calls Using the async/await Pattern A First Look at the C# async and await Keywords (Updated 7.1, 9.0) SynchronizationContext and async/await The Role of ConfigureAwait Naming Conventions for Asynchronous Methods Async Methods That Don’t Return Data Async Void Methods Async Void Methods Using Task Async Methods with Multiple Awaits Calling Async Methods from Synchronous Methods Await in catch and finally Blocks Generalized Async Return Types (New 7.0) Local Functions with async/await (New 7.0) Cancelling async/await Operations Cancelling async/await operations with WaitAsync() (New 10.0) Cancelling async/await operations in Synchronous Calls Asynchronous Streams (New 8.0) The Parallel.ForEachAsync() Method (New 10.0) Update the Book Reader App with async/await Wrapping Up async and await Summary Part V: Programming with .NET Core Assemblies Chapter 16: Building and Configuring Class Libraries Defining Custom Namespaces (Updated 10.0) Resolving Name Clashes with Fully Qualified Names Resolving Name Clashes with Aliases Creating Nested Namespaces Change the Root Namespace Using Visual Studio 2022 Change the Root Namespace Using the Project File The Role of .NET Assemblies Assemblies Promote Code Reuse Assemblies Establish a Type Boundary Assemblies Are Versionable Units Assemblies Are Self-Describing Understanding the Format of a .NET Assembly Installing the C++ Profiling Tools The Operating System (Windows) File Header The CLR File Header CIL Code, Type Metadata, and the Assembly Manifest Optional Assembly Resources Class Libraries vs. Console Applications .NET Standard vs. .NET (Core) Class Libraries Configuring Applications with Configuration Files Multiple Configuration Files Working with Objects (Updated 10.0) Additional Configuration Options Building and Consuming a .NET Class Library Exploring the Manifest Exploring the CIL Exploring the Type Metadata Building a C# Client Application Building a Visual Basic Client Application Cross-Language Inheritance in Action Exposing internal Types to Other Assemblies Using an Assembly Attribute Using the Project File NuGet and .NET Core Packaging Assemblies with NuGet Referencing NuGet Packages Publishing Console Applications (Updated .NET 5/6) Publishing Framework-Dependent Applications Publishing Self-Contained Applications Publishing Self-Contained Applications as a Single File How .NET Locates Assemblies Summary Chapter 17: Type Reflection, Late Binding, Attribute, and Dynamic Types The Necessity of Type Metadata Viewing (Partial) Metadata for the EngineStateEnum Enumeration Viewing (Partial) Metadata for the Car Type Examining a TypeRef Documenting the Defining Assembly Documenting Referenced Assemblies Documenting String Literals Understanding Reflection The System.Type Class Obtaining a Type Reference Using System.Object.GetType() Obtaining a Type Reference Using typeof() Obtaining a Type Reference Using System.Type.GetType() Building a Custom Metadata Viewer Reflecting on Methods Reflecting on Fields and Properties Reflecting on Implemented Interfaces Displaying Various Odds and Ends Adding the Top-Level Statements Reflecting on Static Types Reflecting on Generic Types Reflecting on Method Parameters and Return Values Dynamically Loading Assemblies Reflecting on Framework Assemblies Understanding Late Binding The System.Activator Class Invoking Methods with No Parameters Invoking Methods with Parameters Understanding the Role of .NET Attributes Attribute Consumers Applying Attributes in C# C# Attribute Shorthand Notation Specifying Constructor Parameters for Attributes The Obsolete Attribute in Action Building Custom Attributes Applying Custom Attributes Named Property Syntax Restricting Attribute Usage Assembly-Level Attributes Using a Separate File for Assembly Attributes Using the Project File for Assembly Attributes Reflecting on Attributes Using Early Binding Reflecting on Attributes Using Late Binding Putting Reflection, Late Binding, and Custom Attributes in Perspective Building an Extendable Application Building the Multiproject ExtendableApp Solution Creating the Solution and Projects with the CLI Adding PostBuild Events into the Project Files Creating the Solution and Projects with Visual Studio Setting Project Build Dependencies Adding PostBuild Events Building CommonSnappableTypes.dll Building the C# Snap-In Building the Visual Basic Snap-In Adding the Code for the ExtendableApp The Role of the C# dynamic Keyword Calling Members on Dynamically Declared Data The Scope of the dynamic Keyword Limitations of the dynamic Keyword Practical Uses of the dynamic Keyword The Role of the Dynamic Language Runtime The Role of Expression Trees Dynamic Runtime Lookup of Expression Trees Simplifying Late-Bound Calls Using Dynamic Types Leveraging the dynamic Keyword to Pass Arguments Summary Chapter 18: Understanding CIL and the Role of Dynamic Assemblies Motivations for Learning the Grammar of CIL Examining CIL Directives, Attributes, and Opcodes The Role of CIL Directives The Role of CIL Attributes The Role of CIL Opcodes The CIL Opcode/CIL Mnemonic Distinction Pushing and Popping: The Stack-Based Nature of CIL Understanding Round-Trip Engineering The Role of CIL Code Labels Interacting with CIL: Modifying an *.il File Compiling CIL Code with ILASM.EXE Compiling CIL Code with Microsoft.NET.Sdk.il Projects Understanding CIL Directives and Attributes Specifying Externally Referenced Assemblies in CIL Defining the Current Assembly in CIL Defining Namespaces in CIL Defining Class Types in CIL Defining and Implementing Interfaces in CIL Defining Structures in CIL Defining Enums in CIL Defining Generics in CIL Compiling the CILTypes.il File .NET Base Class Library, C#, and CIL Data Type Mappings Defining Type Members in CIL Defining Field Data in CIL Defining Type Constructors in CIL Defining Properties in CIL Defining Member Parameters Examining CIL Opcodes The .maxstack Directive Declaring Local Variables in CIL Mapping Parameters to Local Variables in CIL The Hidden this Reference Representing Iteration Constructs in CIL The Final Word on CIL Understanding Dynamic Assemblies Exploring the System.Reflection.Emit Namespace The Role of the System.Reflection.Emit.ILGenerator Emitting a Dynamic Assembly Emitting the Assembly and Module Set The Role of the ModuleBuilder TypeC Emitting the HelloClass Type and the String Member Variable Emitting the Constructors Emitting the SayHello() Method Using the Dynamically Generated Assembly Summary Part VI: File Handling, Object Serialization, and Data Access Chapter 19: File I/O and Object Serialization Exploring the System.IO Namespace The Directory(Info) and File(Info) Types The Abstract FileSystemInfo Base Class Working with the DirectoryInfo Type Enumerating Files with the DirectoryInfo Type Creating Subdirectories with the DirectoryInfo Type Working with the Directory Type Working with the DriveInfo Class Type Working with the FileInfo Class The FileInfo.Create() Method The FileInfo.Open() Method The FileInfo.OpenRead() and FileInfo.OpenWrite() Methods The FileInfo.OpenText() Method The FileInfo.CreateText() and FileInfo.AppendText() Methods Working with the File Type Additional File-centric Members The Abstract Stream Class Working with FileStreams Working with StreamWriters and StreamReaders Writing to a Text File Reading from a Text File Directly Creating StreamWriter/StreamReader Types Working with StringWriters and StringReaders Working with BinaryWriters and BinaryReaders Watching Files Programmatically Understanding Object Serialization The Role of Object Graphs Creating the Sample Types and Top-Level Statements Extensible Markup Language (XML) Serializing and Deserializing with the XmlSerializer Controlling the Generated XML Data Serializing Objects Using the XmlSerializer Serializing Collections of Objects Deserializing Objects and Collections of Objects JavaScript Object Notation (JSON) Serialization Serializing and Deserializing with System.Text.Json Controlling the Generated JSON Data Serializing Objects Using the JsonSerializer Including Fields Pretty-Print the JSON PascalCase or camelCase JSON Ignoring Circular References with JsonSerializer