Generics is a concept so ingrained into .NET that we can't do without it.
In this module we'll explain the simple and more advanced things of
- Using Generics
- Creating Generics
- Understanding Covariance and Contravariance
- LAB: Building a Generic Graph
Delegates and Events
Storing functions in variables is exactly what delegates allow us to do.
This concept is used in a lot of locations, especially when using
asynchronous programming. Events are based on delegates, so whenever
something interesting happens in a UI (e.g., mouse click) and we want to
react on it, we need delegates to handle it correctly.
- Creating Delegates
- Using Delegates
- Multicast Delegates
- Creating Events
- Using Events in a UI
- Understanding Closures and static lambda functions
- LAB: Applying Top-down Actions on a Hierarchy
LINQ allows to write queries that are very familiar to SQL queries. This
makes certain operations like filtering and sorting data very easy. This
concept is used in a lot of locations, whether it is to connect to SQL
databases of reading data from Active Directory.
- What is LINQ?
- LINQ to Objects, SQL, Entity Framework and XML
- LINQ's Enumerable Class
- Query Syntax vs. Method Syntax
- Deferred Query Evaluation with Yield Return
- LINQ Operators
- LINQ Internals
- Extending LINQ with your own Operators
- LAB: Exploring LINQ Features
Modern C# Language Features
The C# language itself has evolved dramatically over the last couple of
years. If you have been struggling to keep up with all the details of
these language features, this module is for you.
- Nullable Reference Types
- Value Tuples
- Pattern Matching
- Global and Implicit Usings
- Required and Init-Only Properties
- File-Scoped Types and Namespaces
- Using Raw String Literals
- Required Members
- Generic Attributes
- Specifying the Return Type for Lambda Functions
- LAB: Using ValueTuples with LINQ
When you create an object in .NET, the framework takes care of memory
management for you. But what actually happens with objects when .NET
decides to remove them from memory? That's what Garbage Collection is all
about and we'll have a look at why it is important to understand it
- The Lifecycle of a Class Instance
- GC Class and Members
- Forcing a Garbage Collection
- Garbage Collection for Unmanaged Resources
- The Dispose Pattern
- Weak References
Reference Semantics with Value Types
Writing super-efficient code requires some special language features,
and C# now has them. How to pass value types efficiently? How to avoid
placing transient objects on the heap, and passing them on the stack
instead? And how do you measure the performance gain (or loss)?
- Understanding Reference Semantics
- How Value Types allow you to write faster code
- Passing value types by reference with new access modifiers
- Understanding Span<T> and related classes
- Measuring using BenchmarkDotNet
- LAB: Boosting Performance by using Reference Semantics
How does your machine run multiple processes? How does one process do
multiple things at the same time? In this module, we'll discuss the
advantages and problems you will encounter when using concurrency.
- What is Concurrency?
- Understanding Processes and Threads
- Different Kinds of Concurrency
- Scheduling Threads
Multithreading in .NET
Everyone starts by learning the fundamentals. The Thread class is the most
basic implementation for creating concurrency. It is important to have an
understanding of this class so you can understand and appreciate the
libraries that came afterwards.
- The Thread Class
- Exceptions and Threads
- Understanding Thread Pooling
- Debugging Multi-Threaded Code
Using variables in a multi-threaded environment can be dangerous and
confusing. In this module we'll explain what can go wrong and how to avoid
- Race Conditions and Dead Locks
- Avoiding Race Conditions
- Synchronizing Threads: Locks, Monitors, Signals, ...
- Synchronization Guidelines
- Thread Safety in .NET
- LAB: Horse Race
Using threads directly is quite complicated, instead we can make use of
tasks to do our bidding. There are again advantages and disadvantages to
using this library and we'll explore them in this module.
- What are Tasks?
- Waiting Asynchronously
- Dealing with Exceptions
- Task Cancellation
The Async and Await Syntax Explained
The async and await keywords are amongst the most commonly used language
constructs in .NET. But surprisingly few people know how it actually
- What is Asynchronous Programming?
- Comparing async/await to other Asynchronous Constructs
- Diving into the async and await Keywords
- Understanding ValueTask and its advantages and uses
- LAB: using Async and Await
Asynchronous Programming in .NET
Once you understand the async and await keywords, you can start worrying
about all the other fluff like exception handling, cancellation and
reporting progress of an async task. This is the subject of this module.
- A History of Asynchronous Programming in .NET
- Understanding SynchronizationContext
- Cancellation, Progress and Exception Handling
- Async Guidelines
- LAB: Async and Await in a Library
In a multi-core environment, being able to split data so every core is
working on something is incredibly useful. This module explores a library
created to do just that.
- What is Parallel Programming?
- Writing Parallel Loops
- Concurrent Collections
- Parallel LINQ
- LAB: Parallel Calculations, Parallel API calls
Reactive Extensions (Rx), a feature a bit complex to understand, but very
powerful and hard to get back from. It is sometimes called LINQ to events,
because we think of asynchronous operations or events as a stream of data.
An observable collection that will, from time to time, have a new
interesting event pop up that we can react to.
- Push vs. Pull
- Understanding IObservable<T> and IObserver<T>
- Hot and Cold Observables
- IAsyncEnumerable versus Rx
- What are Subjects?
- Using LINQ with Rx
- Combining Observables
- What about timing?
- LAB: Search Suggestions
Attributes and Reflection
In this module we'll talk about using attributes to add metadata to almost
everything in .NET. Metadata is of course only useful if we can actually
interpret it and that's where reflection comes into play. Reflection is a
powerful feature used in a lot of libraries and applications.
- What are Attributes?
- Applying Attributes
- Common Predefined Attributes
- Building Custom Attributes
- What is Reflection?
- Retrieving Attribute Values
- LAB: Task Scheduler
Expressions and Static Reflection
Making use of Expressions to dynamically create code that can be run when
we want to, is very powerful. It is a feature used by LINQ for example to
translate queries for a database or other system.
- What are Expressions?
- How does LINQ to Database work?
- Using Static Reflection
- Dynamically Generating Code with Expressions
Automating your Code with Source Generators
Source Generators allow to the generate mundane code using the C#
compiler. This allows you to avoid slow reflection and opens the way for
Ahead-Of-Time (OAT) compilation.
- What are Source Generators?
- .NET 7 and 8 Source Generators
- Implementing a Source Generator
- Source Generator Best Practices
- LAB: Building your Own Source Generator