-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
2: Understanding the .NET Ecosystem: Framework, Core, and .NET 5+
If you've spent any time browsing StackOverflow or reading old documentation, you've probably run into the common assumption that ".NET" is just one big, singular thing and that "Framework" and "Core" are just different names for the same set of tools. I see this all the time with developers moving from Java or Python. They think, "I have .NET installed, so I can run any C# code I find online."
That assumption is a recipe for a very frustrating afternoon of compiler errors. To show you why, imagine you've found a great legacy library for handling complex Windows Registry keys written for .NET Framework 4.8. You create a brand new, shiny .NET 8 console application and try to reference that library. You'll likely see a warning or a flat-out failure because System.Web or certain System.Drawing namespaces simply do not exist in the same way in the modern runtime. You can't just "plug and play" because they aren't just different versions—for a long time, they were fundamentally different engines.
"It's all just .NET" vs. The Wall Between Framework and Core
For about two decades, we had .NET Framework. It was the gold standard, but it had one massive limitation: it was married to Windows. If you wanted to run a .NET Framework app, you needed the Windows Registry, the GAC (Global Assembly Cache), and a very specific version of the runtime installed on the OS. It was a monolith.
Then, Microsoft realized the world was moving toward cloud containers and Linux servers. They couldn't just "port" the Framework because it was too bloated with Windows-specific baggage. So, they did something radical: they rewrote almost everything from scratch. This became .NET Core.
Core was lean, fast, and cross-platform. But this created a schism. For several years, the ecosystem was split. You had "Framework" for legacy enterprise Windows apps and "Core" for new, cross-platform microservices. If you're looking at a project today and see net45 or net48 in the project file, you're looking at the old world. If you see netcoreapp3.1, you're in the transition era.
The "Missing Version 4" and The Great Unification
You might notice that the versioning jumps from .NET Core 3.1 straight to .NET 5. I've had students ask me if they missed a year of releases. They didn't. Microsoft intentionally skipped version 4 to avoid confusion with .NET Framework 4.x. They wanted to send a clear signal: .NET 5 is the one true successor.
Starting with .NET 5 (and continuing through 6, 7, and the current 8), we are in the "Unified" era. .NET 5+ is essentially .NET Core evolved. It took the cross-platform nature of Core and added back the compatibility layers needed to support the things people actually missed from the Framework days, like WPF and WinForms (though those still only run on Windows).
Here is the mental model I use:
- .NET Framework: The legacy ancestor. Windows-only. Use it only if you are maintaining a 15-year-old banking app.
- .NET Core: The rebellious teenager. Cross-platform. The foundation for everything modern.
- .NET 5, 6, 7, 8+: The adult. The unified platform. This is where 99% of your new work should happen.
Picking Your Target Based on the Deployment
When you start a project in Visual Studio or via the CLI, you'll be asked to pick a "Target Framework." This is where your understanding of the ecosystem actually matters. If you're building a tool that needs to run on a MacBook, a Linux server, and a Windows laptop, you pick .NET 8. If you're building a plugin for an old piece of industrial software that only supports .NET Framework 4.6.2, you have to target that specifically.
I'll let you in on a professional secret: if you're writing a library that needs to be used by both a legacy Framework app and a modern .NET 8 app, you use .NET Standard. It's not a runtime you install; it's a specification. It's basically a contract that says, "I only use features that exist in both the old and new worlds." It's the "universal translator" of the C# ecosystem.
📋 Practical Task
Audit and Align Project Target Frameworks
You have been handed a small solution containing two projects: a PaymentProcessor class library and a PaymentApi web project. The API is built using .NET 8, but the Library was written years ago and is targeting net472 (.NET Framework 4.7.2).
Your Goal: Resolve the compatibility conflict so the API can use the Library without triggering "Unsupported Target Framework" warnings.
- Open the
PaymentProcessor.csprojfile. - Locate the
<TargetFramework>tag. - Change the target from
net472tonetstandard2.0. - Save the file and attempt to build the
PaymentApiproject. - Observe how changing the library to a .NET Standard target allows the modern .NET 8 API to consume it, while still allowing any legacy .NET Framework apps to use the library.
There are no comments for now.