
This course includes our updated coding exercises so you can practice your skills as you learn.
See a demo
Discover what this ultimate C# masterclass covers and how to set up your learning environment before coding. Get help, ask questions in the Q&A, and access discounts.
Krystyna introduces herself as the course instructor with an applied computer science degree and over a decade of C# development, technical lead experience, and 200+ interviews.
Explore C# fundamentals and beyond, mastering clean code, design patterns, refactoring, data structures, and performance to build apps across platforms while understanding how C# works under the hood.
Clarifies what this ultimate C# masterclass isn't, focusing on deep C# language mastery rather than .NET frameworks, and emphasizes practice to build a solid foundation for desktop, web, and games.
Develop your programming skills through this course, which offers browser exercises, in-video code demonstrations, and quizzes that boost recall as you explore and run the shown code to master C#.
Learn time optimization in the ultimate C# masterclass by adjusting playback and summaries. Use the learning list in resources to tailor your path; most videos are around six minutes.
Install and set up Visual Studio Community on Windows, select .NET desktop development, sign in with a free Microsoft account, and prepare to create a first C# project.
Install the .NET SDK, Visual Studio Code, and the C# Dev Kit extension on macOS; verify the installation with dotnet --info and compare Visual Studio Code with Visual Studio Community.
Access the course code on Windows by downloading the GitHub repository as a zip or cloning it with git, then open in Visual Studio to review exercises and assignments.
On macOS, access the course code from GitHub by downloading a zip or cloning with git, then open in Visual Studio Code, trust the authors, and build to verify.
Kick off your programming journey with the first C# app, learning variables, methods, conditionals, loops, and arrays, completing two simple assignments, while mastering Visual Studio and clean code.
Launch your first C# console program in Visual Studio Community, learn IDE basics, use comments, print to the console, add a wait-for-key line, and configure .NET versions and VS options.
Create your first C# console program in Visual Studio Code, and learn how the IDE helps you write, use comments, print messages to the console, and build with dotnet.
Explore how source code undergoes compilation to become machine-readable files, producing executables (.exe) and libraries (.dll) that the program relies on to run.
Master the most important programmer skill: effectively search for solutions, diagnose compilation errors, and leverage StackOverflow and AI tools to fix bugs.
Learn to implement a simple todo list app with add, view, and remove functions, while practicing printing messages on screen and completing two small assignments toward the final goal.
Explore how variables store values in C#, focusing on strings and ints, and distinguish declaration from initialization. Learn to print with Console.WriteLine and why a variable's type remains fixed.
Learn to name variables in C# with meaningful, lower camel case names, avoid reserved keywords, and use the @ prefix when needed; rename in Visual Studio with Ctrl+R+R for clarity.
Learn the most basic C# operators, including + - * / and unary ++/--, and master operator precedence, string concatenation, mixed-type operations, and the use of parentheses to control evaluation.
Discover how var keyword creates implicitly typed variables in C# by having the compiler infer types from values, and note that you cannot change their types after declaration.
Learn to read user input from the console with Console.ReadLine, store it in a string, print it with Console.WriteLine, and understand code snippets, warnings, and Visual Studio advantages over Notepad.
Learn to debug with breakpoints, inspect variables by hovering, and step through code with F9 and F10, using QuickWatch or the debug console in Visual Studio Code.
Explore the first coding exercise in this course: edit code only in marked areas, run tests, read errors, and compare with solution or hints to improve.
Explore how to add single-line and multi-line comments in C#, use Visual Studio shortcuts to comment and uncomment code, and learn best practices to keep comments meaningful alongside clean code.
Learn how booleans work in C#, using equality and inequality operators to compare values, and apply the logical negation. Explore arithmetic comparison operators and the modulo operator.
Explore and, or, and short-circuiting in C#, learn operator precedence and grouping, place lightweight operations on the left, and name booleans as yes-no questions for clarity.
Learn how if/else conditional statements drive code flow using booleans, string length properties, and multiple execution paths, with practical examples and breakpoints.
Explore how scope governs local variables, using if/else and code blocks to show where variables like userChoice and number are accessible or blocked, including nested if access and separate scopes.
Learn how to define and call void methods in C#, and how parameters and arguments differ, using PrintSelectedOption to reduce code repetition and print messages with Console.WriteLine.
Learn to define non-void methods, use return, ensure every path returns a value, and leverage Visual Studio quick actions to refactor and simplify logic such as IsLong.
Explore statically typed C# and compare with dynamically typed languages, learn to use correct parameter and return types, distinguish runtime from compilation errors, and preview polymorphism.
Discover how parsing converts a string to an int with the int.Parse method, and why console input is read as a string before conversion.
Discover what exceptions are in C#, how a System.FormatException from invalid input can crash an application, and learn to keep asking for valid input while handling and defining custom exceptions.
Learn to add multiple projects to a solution, switch startup projects, and run the active project in Visual Studio and Visual Studio Code.
Tackle your first C# assignment by coding an application based on the described requirements, exploring variables, operators, conditionals, and methods, and learning through guided solutions and online problem solving.
Build a console calculator that prompts two numbers and an operation (a, s, or m, case-insensitive), prints the full expression and result, and handles invalid choices.
build a simple C# console calculator, read string input, parse to int, perform addition, subtraction, and multiplication, and refactor with reusable methods including a case-insensitive equality check.
Learn how string interpolation replaces concatenation by embedding variables and expressions in a single string using a dollar sign, curly braces, and a handy Visual Studio trick.
Learn how switch statements route execution based on an expression, use default for invalid options, and create concise code that handles upper and lower case inputs.
Explore switch expressions and pattern matching in C# 8, refactor traditional switch statements into concise expressions, and leverage constant patterns, relational patterns, and type patterns for readable code.
Learn to use the char type for a single character, replacing strings when appropriate, and enclose chars in single quotes. Strings are collections of chars, as shown by exclamation mark.
Explore loops in C#, covering while, do while, for, and foreach, and how they relate to arrays and lists while building a user input loop that repeats until exit.
Learn to implement a while loop by initializing a counter, incrementing it until it reaches 10, and printing values 1 through 10 to the console.
Discover how the += and ++ operators simplify loop counting and how to prevent infinite loops by proper initialization, with numeric and string examples.
Read a word and append the letter 'a' in a while loop until its length reaches 15, noting that very long input may prevent loop execution.
Explore do-while loops and their difference from while loops, showing that do-while executes at least once and checks the condition after the body with a word longer than ten letters.
Explore the for loop in C#, detailing the initializer, condition, and iterator; print i from 0 to 4, show stepping by two, and note infinite loop risks.
Master the break keyword to control loop execution, stopping loops when a condition is met. Explore do-while loops, user input checks, and a stop command to end loops early.
Explore the continue keyword, skipping the loop iteration when a number is divisible by three, and validate input with All and IsDigit to prevent parse errors in the C# masterclass.
Demonstrate how nested loops work by executing an inner loop inside an outer loop, yielding twelve messages from four outer and three inner iterations and sixty with deeper nesting.
Discover how loop performance affects a program, and learn to avoid degradation by breaking early, moving heavy work outside loops, and optimizing nested loops, with a first look at arrays.
Explore arrays as the basic fixed-size collection in C#, with declaration via new and array initializers. Learn zero-based indexing, end-from-end access with the caret, and the fixed-size disadvantage.
Explore multidimensional arrays in C#, including two-dimensional matrices and three-dimensional cubes. Implement nested loops and use GetLength to access each dimension and print elements.
Use the foreach loop in C# to easily iterate a collection and access each current element, instead of indexing with i, and print elements to the console.
Explore how lists differ from fixed-size arrays and provide dynamic storage in C#. Learn core list methods such as add, remove, removeat, addrange, indexof, contains, and clear, plus foreach iteration.
Learn how the out keyword in C# lets a method return two results, the count of non positive numbers and the positives, for a to do list app.
Parse a string to int safely using TryParse, returning a boolean and an out parameter; practice a do-while loop for valid input, and note the ctrl+k+d formatting shortcut.
Build a console to-do list app that prints all todos, allows adding with non-empty, unique descriptions, and removes by a 1-based index with prompts and input validation.
Implement the todo list app by reading console input in a loop, printing options, using a switch for choices, and adding todos to a dynamic list with non-empty, unique descriptions.
Learn to implement a functional todo list in C# by listing and removing items, converting foreach to a for loop, and printing one-based indices with string interpolation.
Practice refactoring a todo list app by extracting methods, realigning method order, and improving readability with IsDescriptionValid and out parameters.
Learn the basics of object-oriented programming, why we need it, and how to define classes with methods, fields, properties, and constructors, embracing encapsulation, data hiding, and the single responsibility principle.
Analyze the todo list code to see how procedural programming breeds spaghetti code, then learn how object-oriented programming promotes readability, abstraction, and maintainability as requirements change.
Learn how object-oriented programming centers on objects with data and methods, using classes as blueprints to create instances. Explore composition, methods, and core concepts like encapsulation, abstraction, inheritance, and polymorphism.
Explore object-oriented programming by using the DateTime struct to represent dates, access year, month, day, and day of week, and employ the constructor and AddYears method to manipulate dates.
Learn how abstraction exposes only essential data and methods, hiding internal details behind a public interface, as illustrated by DateTime.
Define the first C# class, explain fields and their default values, and introduce the default constructor while modeling a rectangle with width and height.
Learn data hiding by examining private and public access modifiers, understand default private fields, and see how constructors enforce valid state for class members.
Define a custom constructor to initialize width and height, apply field naming conventions, avoid exposing public fields, and note constructor behavior and optional parameter validation.
Learn if C# code can exist outside classes, and how top-level statements in .NET 6 execute at the top of the file while the Program class handles the underlying Main.
Define and name methods in a rectangle class with verbs like calculate area and calculate circumference, understand default private access, and expose needed methods publicly to print results.
Explore encapsulation as bundling data with methods in a class, compare it with data hiding, and learn why keeping area and circumference calculations inside the class enhances clarity.
Discover method overloading in a class, distinguishing overloads by parameter count or type, with examples using DateTime reschedule and a quick constructor snippet.
Learn constructor overloading in C#, call one constructor from another using the this keyword, and avoid code repetition by chaining constructors with parameters like daysFromNow and default dates.
Rewrite small methods as expression-bodied using an arrow, omitting braces and return for a single expression. Learn the difference between statements and expressions and apply it accordingly.
Learn how the this keyword refers to the current instance of a class, enables constructor chaining, accesses private fields via GetDate, and passes this instance to other methods.
Explore how optional parameters define default values in constructors and methods, enabling two call styles with one constructor, while understanding compile-time constants and parameter ordering to prevent ambiguity.
Create a private validator to check constructor parameters and return a default. Use the nameof expression for parameter names and note public fields pose a risk of invalid values.
Learn to prevent field modification using readonly and const, understand immutability, and assign readonly in constructor or declaration; use const for compile-time constants and follow capital-letter naming.
Explore why fields have limitations and how methods and private fields, with getters and setters, support controlled access and validation; learn why properties were introduced in C#.
Explore how properties replace fields with getters and setters and reveal backing fields. Compare fields and properties, and learn when to use public getters with private setters and modern syntax.
Explore how object initializers work with public setters, compare them to constructors. Learn how the init accessor makes properties set only during object construction.
Explore computed properties and when to use them versus parameterless methods, using a rectangle example to show a description property and discuss area and circumference as properties with performance considerations.
Explore static classes and static methods, their limitations, and why const fields are implicitly static, with examples of stateless calculators and calls on the class.
Explore static fields, properties, and constructors and how they belong to the class. See a static count of rectangles with a public getter and private setter.
Explore the single responsibility principle, a core SOLID concept, and see how the Names class mismanages responsibilities by reading and writing a text file.
this lecture demonstrates applying the single responsibility principle by refactoring the names class into five components, introducing a names validator and a strings textual repository for read and write operations.
Explore refactoring within the single responsibility principle by reorganizing class methods, managing access modifiers, and safeguarding data with repositories and public getters, while preparing for automatic unit tests.
Finish refactoring the Names class to satisfy the single responsibility principle by separating file writing and console formatting into dedicated classes, and explain when duplications are acceptable under DRY principle.
Move and organize code by placing each class in its own file. Manage namespaces and using directives, and adopt file-scoped namespaces to simplify C# projects.
Learn how global using directives simplify code across a C# project, measure execution time with Stopwatch, and manage automatically generated usings in Visual Studio with C# 10.
Build a dice roll game as the first object-oriented programming assignment. Practice implementing a class-based design with a random number from 1 to 6, three tries, and input validation.
Learn to generate pseudo-random numbers with the Random class, understand seed and dependencies, implement a dice class with a constructor-injected, readonly Random, and expose a Roll method.
Learn how to avoid the magic number antipattern by using a const integer for the dice sides, enabling easy changes to eight- or twenty-sided dice and preventing hidden bugs.
Design a dice roll game by creating a public game class with a dice object, play method, and replacing the magic number with a constant named InitialTries representing three tries.
Explore enums in C#, learn their underlying int representation, casting between types, and customizing enum values while modeling game results in a dice roll assignment.
Learn to use the ternary conditional operator in a dice roll game, refactor for single responsibility design, organize by namespaces, and prepare for unit testing.
Explore advanced object-oriented concepts like polymorphism, inheritance, virtual methods, abstract classes, and interfaces, apply two design patterns and SOLID principle, manipulate text files in C# to build modular, maintainable code.
Discover how polymorphism provides a single interface for different ingredient types in an object-oriented pizza app, enabling uniform handling while preserving type-specific details and hints toward inheritance.
Explore inheritance in C# by building an Ingredient base class and derived cheese and sauce types, demonstrating is-a relationships and polymorphism within a pizza example.
Explore how base class members are accessible in derived classes via public and protected modifiers, and how derived types override properties like name.
Override base class members in derived classes with the override keyword, and distinguish virtual from non-virtual members and method hiding. Use an ingredients list to demonstrate polymorphism.
Practice virtual methods by refactoring a NumbersSumCalculator to a derived PositiveNumbersSumCalculator, overriding a protected method to add only positive numbers and reduce code duplication through inheritance.
Build an inheritance hierarchy with over two classes, where mozzarella and cheddar derive from cheese, which derives from Ingredient, and show passing mozzarella and cheddar to AddIngredient that accepts Ingredient.
Learn why in C# a class cannot derive from more than one base class and how the diamond problem arises; discover interfaces as a workaround later in the course.
Explore the System.Object base class and its ToString method, see how inheritance provides default behavior, and how overriding ToString customizes object output in C#.
See how the base class constructor runs before the derived one, how the base keyword passes arguments to initialize shared state like PriceIfExtraTopping, and how Cheddar adds its own properties.
Explore how implicit conversion works in C#, highlighting how int converts to decimal behind the scenes, and distinguish it from explicit cast usage with decimal and double types.
Master explicit conversion in c#, contrast with implicit conversion, and highlight when loss of data or runtime errors may require explicit casting, using int, decimal, enums, and ToString.
Examine the difference between upcasting and downcasting in C#, why upcasting is safe, why downcasting risks invalid casts, and how explicit casts or the is operator improve safety.
Explore the is operator to safely check an object's type, demonstrate upcasting and downcasting between Cheddar, ingredient, and object, and illustrate implicit versus explicit conversions.
Explore null in C# by examining default values for fields and properties and using is not null checks to avoid NullReferenceException. Learn which types cannot be null.
Explore the as operator in C#, its limitations, and how it differs from explicit casting. As returns null on failure for nullable types, requiring null checks to avoid NullReferenceException.
Understand abstract classes and how to prevent instantiation, using ingredient as a base example. Recognize that every ingredient has a name and a price, and that ToString returns the name.
Explore abstract methods and properties in abstract classes, and why derived non-abstract types must override them, with virtual vs abstract distinctions and ingredient examples.
Understand why abstract methods are needed and how they differ from virtual methods. Learn how abstract base methods enable polymorphic calls on derived ingredients and ensure derived classes implement Prepare.
Learn how sealed classes and methods prevent inheritance with the sealed modifier, illustrated by Mozzarella and TomatoSauce, and understand why sealing is a deliberate design choice with limited use.
Learn why static classes are implicitly sealed and why static methods can't be overridden, then call static methods on the class name to generate a pizza with random ingredients.
Learn how to define extension methods in a static class, use the this parameter to extend types like strings and enums, and call them as if they were instance methods.
Discover why abstract classes fail for common bakeable items and learn to use interfaces in C# through a pizza and panettone scenario, implementing a GetInstructions method.
Explore how interfaces define contracts that enable disparate types to share behavior, such as flyable and bakeable. Learn to implement and use them across classes in C#.
Explore the key differences between interfaces and abstract classes, including how interfaces define behavior without implementation and how abstract classes provide common structure and partial implementations.
Explore what JSON and XML are, serialize a C# object to JSON, and deserialize JSON back to a C# object using System.Text.Json's JsonSerializer, with string escaping and error handling.
Create a cookie recipes app that saves recipes to txt and json files, letting users enter ingredient IDs via the console to build and store recipes.
Define the high-level logic for the cookies cookbook app, design its public interface, and implement a workflow that reads, prints, and saves recipes with the single responsibility principle.
Explore the dependency inversion principle and dependency injection to decouple app logic from user interfaces using abstractions like IRecipesUserInteraction, and apply target-typed new expressions in C# 9.
Design data types for a cookie cookbook, modeling Recipe as a wrapper for ingredients and an abstract Ingredient, using IEnumerable to prevent modification and prepare for generics.
Explore the LINQ library and IEnumerable concepts while implementing a recipes repository, printing existing recipes, and building ingredient strings; learn how extension methods and foreach loops enable flexible data handling.
Develop a generic storage class and an ingredients register to print each ingredient with its ID, override Ingredient.ToString, and integrate into the PromptToCreateRecipe workflow while addressing a compilation error.
Continue implementing the cookies cookbook app by reading user ingredient IDs in a loop, parsing input, retrieving ingredients with GetById, and assembling a recipe from an IEnumerable.
Practice reading from and writing to a text file by using a strings repository and an interface for dependency inversion. Transform recipes into comma-separated IDs and test handling non-existent files.
Practice reading from and writing to a json file, using a strings repository pattern with StringsJsonRepository and StringsTextualRepository, and serialize ingredient IDs as a json array, while RecipesRepository remains unchanged.
Explore the template method design pattern by refactoring two IStringsRepository implementations into an abstract base class, with abstract textToStrings and stringsToText steps for transforming text from text files and JSON.
Organize a cookies cookbook project by refactoring into focused namespaces, moving data access types to DataAccess and file access to FileAccess, and adopting file-scoped namespaces via Visual Studio refactor actions.
Learn to handle exceptions in C# by exploring error scenarios from division by zero to out-of-memory, and apply approaches that prevent crashes and make issues easy to find and fix.
Explore how exceptions work in C#, inspect the System.Exception object with its Message, InnerException, and StackTrace, and view details via the QuickWatch window while recognizing runtime errors and custom exceptions.
Learn how stack traces reveal the origin of exceptions, why unhandled errors frustrate users, and how detailed messages and breakpoints help diagnose issues in C# applications.
Master handling exceptions with try-catch-finally in C#, compare try-parse versus parse, use specific catch blocks, ensure cleanup in finally, and log messages with nameof.
Learn how to catch specific exceptions with multiple catch blocks, order them from most to least specific, and handle FormatException and DivideByZeroException precisely in C#.
Throw exceptions to signal invalid input when a method cannot return a value. Use clear messages and specific exception types, shown by a first element method and a person constructor.
Explore built-in C# exception types such as ArgumentException, ArgumentNullException, ArgumentOutOfRangeException, IndexOutOfRangeException, and InvalidOperationException, with notes on their use in constructor validation and LINQ First, plus NotImplementedException for stubs.
Explore the StackOverflowException and recursive methods, learn how the stack trace reveals excessive calls, and implement a stopping condition with a counter example to prevent stack overflow.
Master precise exception handling by avoiding the base System.Exception, and favor specific exceptions like InvalidOperationException and ArgumentNullException, possibly wrapping the original with InnerException.
Explore how to rethrow exceptions correctly by using throw, not throw ex, to preserve the stack trace, and use InnerException to retain the original error origin.
Learn to handle unknown exceptions by catching the base System.Exception, log the error, and rethrow, as shown in ReadPersonData calling Read on a PeopleRepository implementing IPeopleRepository.
Implement a global try-catch around the application entry point, the main method, to catch any exceptions. Show the user a message, log the exception, and shut down the application gracefully.
Learn what to place in a catch block and why throwing inside a catch is risky; avoid nested try catch and rely on a global handler as a last resort.
Learn how to use exception filters to distinguish same-type exceptions by conditions, apply specific catch blocks for HTTP status codes, and order filters from specific to generic.
Learn how to define custom exceptions by deriving from the exception base, name them with the Exception suffix, and implement constructors for message and inner exception.
Evaluate when to define custom exceptions versus using built-in types, guided by the principle of least surprise and the need for meaningful data like JsonParsingException.
Recognize that exceptions form a hidden part of a method's signature, potentially changing behavior unseen. Prefer compilation errors over runtime surprises when external libraries change what a method may throw.
Examine the drawbacks of exceptions, compare them to goto, and explore alternatives that balance performance and code clarity, including functional-style results and explicit error handling.
Learn to use exceptions wisely by deciding when to throw them and when to catch them. See examples from null or empty collections, JSON deserialization, and other common error scenarios.
Catch exceptions only when you can act on them, using specific types and returning null or retrying on timeout. Use a global catch for unhandled errors and avoid duplicate logs.
Develop an app that reads video game data from a JSON file, parses it, prints the games to the console, and gracefully handles missing files with file-based error logs.
Implement the game data parser assignment by deserializing json into a video game class and explore exception handling from no checks to try-catch to refactoring in the sunny day scenario.
Explore how exceptions control program flow, use the default keyword, and handle null, empty, and missing file names with catches, preparing for JSON deserialization of a list of video games.
Wraps json deserialization errors into a new JsonException with the file path, logs the inner exception, prints a red error message, and guides graceful shutdown when invalid json is detected.
Create a logger for the game data parser that appends exception details: date, message, and stack trace to a log file; use a global try-catch and compare log4net and Serilog.
Reduce try-catch usage by replacing checks with if statements while preserving user feedback and global error handling. The lecture demonstrates balanced exception handling, including JSON deserialization and file path context.
Refactor the Run method by extracting ReadValidFilePathFromUser, reading file contents, deserializing JSON, and printing games, forming a four-step workflow toward better single-responsibility design.
Refactor the game data parser to enforce the single responsibility and dependency inversion principles by introducing interfaces and dedicated classes, enabling decoupled workflows, flexible user interaction, and modular data reading.
Master generic types and their definitions to write shorter, reusable code. Explore methods as arguments, delegates, lambda expressions, and common patterns, plus dictionaries and a simple cache.
Explore how generic types in C# use type parameters like T to create reusable lists, interfaces, and methods, and see how List<T> supports Add, Clear, and IndexOf.
explore how the list works under the hood by examining its underlying array, _size tracking, and Add and Remove operations, including resizing, copying, and performance implications.
Implement a simplified int list class, first non-generic then generic to illustrate lists. Double the internal array when full and track size using the Add method, starting at capacity four.
Enhance a simple list by implementing RemoveAt with bounds checking, shifting elements left, and zeroing the last slot; learn indexers and add GetAtIndex, preparing for generics.
Explore why generic types matter, implement a single generic SimpleList, use default(T) to reset elements, and illustrate type parameterization and inference across numbers, strings, and DateTimes.
Demonstrates returning multiple values with tuples, contrasts int.Parse and int.TryParse with out parameters, and implements a min-max algorithm using a flexible container type.
Define a generic two-item tuple with type parameters T1 and T2, demonstrate using both custom SimpleTuple and built-in tuples, and show three-item variants and value tuples.
Explore how pre-generics C# used ArrayList to store objects, exposing type safety issues, casting and boxing costs, and performance drawbacks. Learn how generics, such as List<T>, improve reliability and efficiency.
Learn how to define generic methods and extension methods, how the compiler infers type parameters from context, and how static ListExtensions enables AddToFront for lists of any type.
Learn to define generic methods with multiple type parameters and convert a list from one type to another by casting items, using a ListExtensions ConvertTo method with TSource and TTarget.
Explore Convert.ChangeType to convert any type to any other, using the Type class, typeof, and GetType, with examples across decimals, ints, floats, and longs.
Explore type constraints and the where keyword to enforce a public parameterless constructor for generics, enabling safe creation of T instances and practical use with int, DateTime, and more.
Learn how list resizing affects performance when adding many items and how pre-sizing the list with a capacity avoids costly copies, and measure time with Stopwatch to show performance gains.
Apply type constraints to limit generics to types derived from a base class, such as Person and Employee, enabling collections of employees and their GoToWork usage.
learn how the IComparable interface enables sorting by implementing CompareTo, and sort a list of people by year of birth, placing younger first and older last.
Explore generic type constraints in C#, restricting types to those implementing the IComparable<T> interface, and use CompareTo to order values for ints, strings, and person objects.
Learn how to constrain type arguments to numeric types using generic math in C#, enabling methods to work with any numeric type via the INumber interface from System.Numerics.
Explore type constraints in c#, including applying multiple constraints to single and multiple type parameters with the where keyword, and examples like TPet derives from Pet and TOwner's parameterless constructor.
Explore the advanced use of methods, storing them in variables and passing them as parameters, and learn about Funcs and Actions to master LINQ and modern C# coding.
Learn to assign methods to variables, use Func and Action to pass functions as parameters, and refactor to a single IsAny method with a predicate.
Learn how lambda expressions define anonymous functions to perform concise, specific checks, infer parameter types, and use with LINQ and the Func and Action types.
Explore what delegates are, how multicast delegates work, and why modern C# favors Func and Action over custom delegates.
Master the basics of C# dictionaries: map country names to currencies, ensure unique keys with Add versus the indexer, and initialize or update entries using ContainsKey and collection initializer approaches.
Practice using dictionaries by grouping employees by department and calculating each department's average salary, building a dictionary of department names to averages.
Explore the strategy design pattern to filter numbers by even, odd, or positive criteria, then refactor with a NumbersFilter and FilterBy, using dictionaries and Funcs for extensibility.
Refactor the code by using funcs and lambda expressions to consolidate three similar methods into one predicate-driven method, then switch and use select to apply the chosen filter.
Explore the strategy design pattern and the open-closed principle by replacing a switch with a dictionary of funcs to select filtering at runtime without modifying existing code.
Access dictionary keys to list filtering strategies and expose them via a keys collection. Implement a generic filter for any IEnumerable<T>, echoing LINQ Where.
Cache data in memory to serve repeated requests faster, balancing memory use with quicker access and applying eviction and freshness checks for external data or locally calculated results.
Create a generic cache class to cache data by any kind of id and any data type, use dictionaries and Funcs, and demonstrate faster retrievals after the initial slow fetch.
Define a generic cache with a dictionary by implementing a Cache class and a Get method that accepts a first-time fetch function, storing data by key for reuse.
Discover how the decorator design pattern adds a caching feature to a data downloader without modifying existing code, enabling optional caching and Open-Closed Principle adherence.
Master the decorator design pattern by composing multiple IDataDownloader decorators, adding caching and console printing to enhance data retrieval while upholding the open-closed principle.
Explore LINQ, a core C# library for manipulating collections through ordering, filtering, and transforming data, and learn how LINQ works under the hood, with coding exercises and refactoring challenges.
Discover LINQ, a language integrated query that enables filtering, ordering, and transforming collections. Write concise code with method syntax and lambda predicates.
explore how linq extension methods let Where work on lists and arrays by extending IEnumerable of T, with Enumerable providing the implementations and global usings enabling System.Linq.
Explore how LINQ uses extension methods on IEnumerable<T>, and master method chaining to create new, non-mutating collections with sequential operations like where and orderBy.
Understand deferred execution in LINQ, where evaluation is delayed until needed, improving performance and reflecting latest data. See how ToList or Take influence materialization and show queries are not data.
Learn to use the LINQ any method to check if any element in a collection satisfies a predicate, using a lambda like x > 10.
Use the all method to verify every element satisfies a predicate, mirroring the any method. See examples where all numbers are greater than zero and all pets have non-empty names.
Master Count and LongCount to tally collection elements with a predicate, see examples like dogs under ten kilograms or pets named Bruce, and use LongCount for results that exceed int.
Learn to use the contains method in LINQ to check whether a collection contains a given element, illustrated with seven and tiger, and see true or false results from equality.
Learn to order collections with LINQ using OrderBy and OrderByDescending, which return ordered sequences without modifying input. Chain ThenBy to sort by criteria, such as pets by type and name.
Learn how to use the first and last LINQ methods, with and without predicates, handle empty collections with FirstOrDefault and LastOrDefault, and apply order by to identify extremes.
Learn how the where method in LINQ filters collections with predicates, returning a new collection. Explore the index-aware overload, complex predicates, and practical UI use cases.
Master the Distinct method to remove duplicates from any collection, returning a collection of unique elements, with examples for strings and practical use in C#.
Master the LINQ select method to transform collection elements with a lambda, produce new collections, and even change the type of the output.
Explore anonymous types in C# and use them with LINQ to compute per-list counts and averages, order results by average descending, and carry temporary data between queries.
Refactor cookie cookbook project by replacing foreach loops with LINQ queries, using Select to convert recipe strings to Recipe objects and ToList to create the List from the read method.
Refactor the recipe parsing and writing logic with LINQ by mapping comma-separated IDs to ingredient objects, using select to transform data, and prioritizing readability over overly compact code.
Discover how to use the Visual Studio find and replace window to locate foreach occurrences and prep for LINQ refactoring, exploring match case, whole word, and regex options.
Refactor the cookie cookbook app using LINQ to replace foreach loops and improve multiline string literals formatting. Build the output with Select and string.Join, handling the index carefully.
Practice refactoring with LINQ to efficiently check for duplicates and find items by predicate, using FirstOrDefault, Where, and Count to balance performance and correctness.
Explore how memory is managed in .NET and how to release resources efficiently. Delve into the low-level mechanics of .NET to boost performance and reduce memory usage.
Explore what .NET is and how it differs from C#, see other languages that run on .NET, and review Common Language Runtime and frameworks like Windows Forms and ASP.NET MVC.
Explore what the common intermediate language is and how the just-in-time compiler translates CIL to binary at runtime, enabling communication between C#, F#, and VB.
Explore the Common Language Runtime, the .NET execution engine that manages memory, garbage collection, exceptions, and threads, enabling cross-language interoperability and seamless application execution.
Discover how memory is organized in .NET by comparing the stack and the heap. See how the Common Language Runtime uses the garbage collector and why the stack performs better.
Explore value semantics with integers and value types, showing how copying preserves independence, and contrast with reference semantics using a Person class where multiple variables share the same object.
Understand value types versus reference types in C#, including structs and the role of System.ValueType and System.Object, and how copying differs for parameters—values copy data, references copy references.
Explore practical tips on value versus reference types, the effects of turning a class into a struct, and how immutable types support safer, non-destructive mutation.
Explore the ref modifier, compare ref and out parameters, and learn how passing by reference affects value types, initialization rules, and when to favor returning values or tuples for clarity.
Explore how the ref modifier handles parameters of reference types, including copying references, shared mutations, and how null affects the outer variable.
Discover how C# implements a unified type system by treating all objects as System.Object, enabling you to store diverse data and understand boxing and unboxing.
Learn boxing and unboxing in C#, including how value types box when assigned to object types, how boxed values live on the heap, and how unboxing requires exact type matches.
Analyze the performance cost of boxing and unboxing and reference sizes in C#. Compare ArrayList and generic lists for value types; explain boxing when values or interfaces require reference types.
Discover how the .NET garbage collector manages heap memory and object lifecycles, when it triggers, and how pauses can impact performance. Learn about pooling and defragmentation to minimize GC pauses.
Learn how memory fragmentation occurs and how the garbage collector uses defragmentation to move memory blocks, creating larger contiguous free space for storing large objects like long strings.
Explore how the garbage collector uses mark-and-sweep to remove unreachable objects, and compare it with reference counting and tracing, including circular references and application roots.
Explore how the garbage collector uses generation zero, one, and two to optimize performance. Learn about large objects heap and pinned objects, and how defragmentation follows removal of unreferenced objects.
Explain memory leaks and show how static fields can cause leaks by maintaining a static list of all instances, keeping objects reachable by the garbage collector.
Explore destructors, also known as finalizers, and their use cases, including translation to Finalize, why you must not call Finalize, and how to clean resources with IDisposable.Dispose.
Learn how the Dispose method from IDisposable frees unmanaged resources while distinguishing managed resources handled by the CLR, and implement cleanup code such as closing database connections.
Create a file-writing class using StreamWriter, with the file path and an append flag in the constructor, writing lines with WriteLine and calling the Flush method to save.
Read a specific line from a text file with StreamReader using ReadLineNumber and ReadLine in a skip loop, then ensure disposal of unmanaged resources via Dispose.
Learn how to implement the IDisposable interface and the Dispose method, and use the using statement to free unmanaged resources and prevent file access errors.
Learn what CSV files are and why they appear in real-world data work. Explore comma separated values, their tabular structure, and the role of spreadsheets in storage and assignments.
Build a simple CSV reader in C# that loads data into a CsvData object with columns as string[] and rows as IEnumerable<string[]>, reading with StreamReader and splitting lines by commas.
Improve a csv reader's performance and memory usage by implementing fast table data building, optimizing GetValue calls, and aligning types with int, decimal, bool, or string.
Analyze the Build method in the TableDataBuilder for CSV data, detailing row iteration, type conversion rules (true/false, decimal then int), and improvements to avoid empty-cell dictionaries and boxing.
Reduce the size of a CSV row dictionary by omitting empty cells with a fast table data design, achieving nine times lower memory use and faster loading.
reduce boxing in csv processing by using separate dictionaries for ints and bools, avoiding boxing and lowering memory use, while assessing dataset-specific performance trade-offs with the fastrow data structure.
Analyze performance trade-offs in csv processing by comparing one versus four dictionaries, highlighting memory, boxing costs, and configurable choices based on column count and use case.
Explore C# types beyond classes and enums, including structs and records, and learn how to choose the best fit, plus reflection and the System.Object type for consuming web API data.
Explore reflection and the Type object to inspect types at runtime. Read property names and values, build text with LINQ, and discuss benefits and downsides.
Explain what attributes are and how to create and apply a custom string length attribute, and use reflection to read metadata, validate properties, and implement a validator.
Explore the limitations of attribute parameter types in c# and learn which types are valid, including bool, string, basic numerics, enums, Type, System.Object, and arrays.
Learn what structs are and how they differ from classes. Discover why structs should be small, and how struct and class constraints govern value types and their semantics.
Explore the crucial differences between structs and classes, including value types versus reference types, nullability and default values, why structs are sealed and non-inheritable, and how boxing occurs with interfaces.
Explore low-level differences between value types (structs) and reference types (classes) in C#, including constructors, finalizers, copying behavior, and cycle restrictions, with guidance on when to use each.
Choose structs for value type semantics and small, data-centric types, and use classes for reference type semantics. Keep structs immutable and avoid reference types inside them, noting strings as exception.
Learn why making structs immutable is beneficial, preventing unintended changes and refactoring pitfalls. See how init accessors enforce immutability and why built-in structs like datetime are typically immutable.
Discover non-destructive mutation in C#, keeping structs immutable by creating a new object when modifying values, such as adding seven days with the DateTime AddDays method.
master the with expression for non-destructive mutation of structs in C# 10, enabling copy-and-modify of properties without altering the object, works with structs, records, record structs, and anonymous objects.
Enforce immutability in C# structs by using the readonly keyword, making fields readonly and properties get-only or init-only, with the compiler flagging violations.
Examine the System.Object methods and use ReferenceEquals to compare object references, highlighting differences between reference types and value types, boxing, and null handling.
Explore how the System.Object Equals method behaves by default: reference equality for reference types and value-based equality for value types, with the method being overrideable.
override the Equals method in the Person class to compare objects by id using the is operator and null checks, and note that GetHashCode should accompany Equals for consistency.
Learn why overriding equals in structs improves performance by avoiding reflection, how Visual Studio generates equals, and when to compare IDs or fields like X and Y.
Learn how the IEquatable<T> interface provides a type-specific Equals(T) to avoid boxing, and how Contains uses this method (unlike IComparable) to optimize equality checks.
Explore how the equality operator differs for reference types, which compare references. Enable value-based equality for value types by overloading the operator or overriding the Equals method.
Learn how operator overloading works in C#, including overloading addition, equality, and inequality for custom types like a point struct, and understand which operators can and cannot be overloaded.
Explore how to overload implicit and explicit conversion operators in C#, and learn when to apply each to convert types like tuples to a Point type safely.
Explore hash functions and the GetHashCode method in C#, learn how object components form hash codes, why collisions occur, and how dictionaries use hash keys for fast lookups.
Learn how the default GetHashCode works for reference types versus value types. See why dictionaries use hash codes to distinguish keys and when to override the default implementation.
Override GetHashCode when the default fails, and keep it consistent with Equals by using the ID property; for hashed collections like dictionaries, override both Equals and GetHashCode.
Override the GetHashCode method by using HashCode.Combine to merge the X and Y fields for point, and the ID for person, ensuring equal objects share hash codes for hash-based collections.
Explore ValueTuple and how it differs from tuples: a mutable value type with named fields, vs immutable reference tuples, covering creation, item access, GetHashCode, and value-based equality.
Explore immutable types and pure functions, their testing benefits, and discuss downsides like non-destructive mutation costs and garbage collection in multi-threaded environments.
Learn how records provide value-based equality and immutability in C# 9, compare positional and non-positional records, and use the with syntax for non-destructive mutations.
Explore record structs in C# 10, their value-type semantics, equality, and immutability, and compare them with records to decide when to use each.
Explore nullable value types in C# using int? and Nullable<T> to represent missing values. Learn HasValue and Value, safe unboxing, and how nulls affect averages.
Explore nullable reference types in c# 8, learn how to enforce non-null values via constructors, and understand compiler warnings and ide support to reduce null reference exceptions.
Explore the null-forgiving operator, suppressing nullable warnings in a class with an init method. Understand handling Visual Studio warnings, null checks, and optional disabling of nullable reference types.
Enable nullable reference types in C# 8+ to reduce null checks, using preprocessor directives to toggle per file. Explore generic type constraints for nullable and non-nullable types to improve safety.
Learn what apis are and how they enable software components to interact via web endpoints and json data, including open public versus internal apis.
Learn to query public APIs in C# using HttpClient, perform asynchronous GetAsync calls with await, and extract JSON while handling authorization and API limits.
Create an ApiDataReader class to read JSON from an open API and deserialize it into C# objects using System.Text.Json. Understand async methods, the await keyword limitations, and returning Task results.
Query the Star Wars API to fetch ten planets, deserialize JSON, and display planet’s name, diameter, surface water percentage, and population, with user choosing property to reveal max and min.
Implement the assignment by reading data from the Star Wars API, deserializing json with JsonPropertyNameAttribute, and introducing DTOs for data transfer.
Practice handling exceptions in api calls, identify potential throws with documentation comments, and implement a global try-catch and dependency inversion for resilient Star Wars planet stats data.
Design a planet data model in C# by using a readonly record struct, choosing value types, and converting a JSON dto to a nullable, immutable planet collection.
Convert a dto to a planet type via an explicit operator, parse diameter with int.Parse, and use TryParse for population and surface water, while considering dto versus type separation.
Finish the assignment by using LINQ's MaxBy to find planets with max and min population, diameter, and surface water, then refactor with ShowStatistics to print results using a planet selector.
Learn core refactoring: replace long if-else with a dictionary mapping of planet properties to functions, leverage code analysis hints and the null coalescing assignment operator, and streamline to reduce duplication.
Split the main class into smaller classes to comply with the single responsibility principle. Move planet reading to an IPlanetsReader implementation, enabling future data sources like databases or CSV files.
Learn to build a generic table printer using reflection to print any type's properties in a fixed 15-character column width, with headers, lines, and long population handling.
Explore C# collections, compare their performance, and learn algorithm complexity with Big O notation, the yield keyword, a SOLID principle, and implement a linked list from scratch.
Explore the core collection interfaces in C#, focusing on IEnumerable and its role in foreach and LINQ. See how non-generic and generic IEnumerable enable collections, with strings as char collections.
Explore the IEnumerable interface and its enumerator mechanics for safe, non-modifying iteration. See how GetEnumerator, Current, and MoveNext drive foreach as a generated while loop using IEnumerator.
Implement IEnumerable in a custom collection to enable foreach, using a WordsEnumerator with a private current index, a Current property, MoveNext, and a GetEnumerator returning IEnumerator.
Explore implementing the generic IEnumerable<string> with the non-generic IEnumerable to enable for-each iteration over strings, resolve GetEnumerator conflicts with explicit interface implementation, and understand explicit versus implicit usage.
Implement the generic IEnumerable<T> with explicit interface members, explore backward compatibility and named arguments, ensure IDisposable compliance, and verify that iterated elements are strings.
Explore indexers in C#, define custom indexers for collections, use integers or keys like strings, and understand getters, setters, and when to omit them.
Enable collection initializers for a custom collection by providing a parameterless constructor and a public add method (which may be an extension), allowing initialization like a list.
Explore the generic ICollection<T> and IList<T> interfaces, including CopyTo usage, readonly status, and how List copies collections, then examine how IList<T> extends ICollection<T> with an indexer and index-based methods.
Examine how arrays explicitly implement ICollection, enabling add calls that a fixed-size array cannot support. See the exception and learn why this illustrates a violation of the interface segregation principle.
Master the interface segregation principle from SOLID and why interfaces should avoid forcing unused methods. Discover splitting interfaces into readonly and add or remove parts to prevent array misuse.
Discover how readonly collections enforce immutability, making code easier to follow, enabling pure methods, and supporting easier multithreading, while keeping data valid and easing testing.
Discover how to create truly read-only collections in C# with ReadOnlyCollection and ReadOnlyDictionary, instead of returning IEnumerable and risking modification through casting.
Explore Big O notation and how algorithm cost scales with input size, comparing constant, linear, logarithmic, and quadratic complexities, plus time and space considerations.
Master the binary search algorithm and its divide-and-conquer approach to locate an item in a sorted collection, returning its index and halving the search range each step.
Implement a binary search algorithm in C# as an extension method for IList<T>, with IComparable constraints, returning the index or null by using leftBound and rightBound.
Explore the time complexity of binary search and its logarithmic behavior (big o of log n, base two), and learn to use the built-in BinarySearch for sorted collections.
Improve list performance in c# by using constructors and capacity, and AddRange for bulk adds; TrimExcess frees memory. Generate large sequences with Enumerable.Range and use underscores for readability.
Define a linked list with nodes holding a value and a next reference, and explain head, singly and doubly variants. Prepare for an assignment to implement a custom linked list.
Compare linked lists and plain lists in C#, highlighting access by index, insertion at beginning and end, deletion, memory usage, and Big O performance to guide data structure choice.
Explore how dictionaries use a hash table of linked lists to store key-value pairs, handle collisions, and retrieve items via hash codes, Equals, and GetHashCode methods, noting dictionaries are unordered.
Explore how dictionaries achieve near constant time for get, add, contains, and remove thanks to hash codes, array lengths, and few hash code conflicts.
Learn how a hash set stores unique values and provides fast contains checks, preventing duplicates; use Distinct or convert to a hash set to remove duplicates, with order not guaranteed.
Explore how queues implement the first-in, first-out principle using the C# Queue class, with Enqueue, Dequeue, and Peek operations; learn about priority queues and real-world analogies.
Learn the stack data structure and the last in, first out principle, with push, pop, and peek at the top. See how stacks support memory, function calls, and undo actions.
Master the params keyword to accept any number of arguments as a single-dimensional array, while preserving backward compatibility and avoiding new overloads.
Explore why yield statements matter in C#, showing how to generate sequences efficiently and control resource use, including skipping items and taking a subset.
Show how yield return streams values one by one in a for-each loop, producing a sequence that interleaves execution with GenerateEvenNumbers. Explore how breakpoints and console messages reveal this behavior.
Learn how yield statements create lazily evaluated iterators, what IEnumerable means, and how foreach drives execution, highlighting why iterators can be more efficient than building large collections.
Master iterators by using yield return and yield break to control iteration flow, and implement a hash set based distinct method with a numbers example.
Explore implementing the IEnumerable interface with iterators and yield return in C#, using GetEnumerator, explicit generic IEnumerable, array wrappers, and a custom WordsEnumerator to compare options.
Learn to build a custom linked list in C#, defining node and list types, storing data and implementing ICollection and IEnumerable with add to end, remove, and enumerator methods.
Design a nullable, generic singly linked list in C# by building a node with value and next, managing a head and count, overriding ToString, and implementing the linked list interfaces.
Implement the AddToFront method in a custom linked list by creating a node, making it the head, linking the previous head as its successor, and incrementing count in constant time.
Implement the GetEnumerator method using a private iterator to traverse all linked list nodes, enabling foreach iteration and yielding node values via GetNodes before exposing IEnumerable.
Implement the Add method for a linked list by calling AddToEnd to append at the end; if empty, create head, otherwise locate tail with GetNodes and LINQ's Last.
Implement the linked list clear method and learn why modifying a collection during iteration is risky. Use a ToList snapshot or a safe loop instead.
Implement remove and contains for a custom linked list by locating first matching node, updating the predecessor, and adjusting head or tail; use Any to handle nulls and return boolean.
Finish implementing a custom linked list and the CopyTo method to copy items into an array starting at a specified index, with argument validation and a simple fill loop.
Review the singly linked list implementation and compare it with the built-in linked list, focusing on performance, nested private Node classes, and operations like remove, clear, and add to end.
Welcome to the "Ultimate C# Masterclass" course - the only course you need to master C#!
With 47 hours of video, 67 coding exercises, 86 quizzes, and 16 assignments, this course is packed with hands-on learning.
As a .NET Technical Lead with over a decade of experience, I'll be guiding you every step of the way—whether you're a complete beginner or an experienced developer looking to level up.
Why learn C#?
C# is the backbone of modern software development, powering desktop applications, web services, cloud computing, and game development with Unity.
Mastering C# isn’t just about learning syntax—it’s about writing efficient, maintainable, and professional-grade code. That’s exactly what this course will teach you.
What makes this course different?
We go beyond syntax. You'll learn why all the things we learn are needed and how to use them right.
We emphasize clean code and good design principles from the start.
Design patterns will be demonstrated in practice, not just as abstract concepts that seem impossible to apply in real-world challenges.
Refactoring will be something we practice all the time.
You'll gain hands-on experience through implementing various projects, from processing API data to analyzing PDF files.
You'll learn how things work under the hood, and thanks to that, you will gain an in-depth understanding of C#.
You'll master asynchrony, multithreading, and performance tuning.
You'll practice unit testing with NUnit and Moq to build reliable software.
No fluff. No endless theory. You’ll learn by doing. You will solve dozens of coding exercises right in the browser.
Additional perks:
Full Git repository with all code shown in the course.
This course is covered by Udemy’s 30-day Refund Policy, so you can try it out risk-free.
C# is one of the most in-demand programming languages today. Learn it the right way and accelerate your career.
Enroll now and start coding like a pro!