C#
Completed
-
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
59: Anonymous Types
A few years ago, I was working on a dashboard for a logistics company. I needed to pull a list of shipments, but the UI only cared about three things: the tracking number, the destination city, and whether it was delayed. The Shipment object in our database had about 40 properties—weight, dimensions, customs codes, the works. I started by creating a new class called ShipmentSummaryViewModel just to hold those three fields. Then I realized I was spending more time writing boilerplate "DTO" classes for every single little view in the app than I was actually writing logic. It felt like I was fighting the language just to move a few pieces of data around.
Disposable Data Containers
This is where anonymous types save your sanity. Instead of defining a formal class for a temporary data structure, you can tell C# to "just figure it out" on the fly. You do this using the new keyword without specifying a type name, combined with the var keyword since the type doesn't actually have a name you can type out.
var shipmentSummary = new {
TrackingId = "ABC-123",
City = "Seattle",
IsDelayed = true
};
Console.WriteLine($"Shipment {shipmentSummary.TrackingId} is headed to {shipmentSummary.City}");
When you write this, the compiler is doing some heavy lifting behind the scenes. It generates a temporary class for you, assigns the properties, and ensures they are read-only. You aren't creating a dynamic object; this is still strongly typed. If you try to assign a value to shipmentSummary.City after it's created, the compiler will stop you. I personally love this for LINQ projections—it's the primary way we shape data coming out of a database without polluting our namespace with a dozen "Summary" or "Projection" classes.
Where Anonymous Types Hit a Wall
Now, it's tempting to use these everywhere, but there's a catch: scope. Because the compiler generates a name for this type that only exists within the method, you can't easily pass an anonymous type as a parameter to another method or return it from one. If you try to change a method signature to return an anonymous type, you'll find yourself forced to return object or dynamic, which completely defeats the purpose of having strong typing.
If you find yourself needing to pass that data across different layers of your application, that's your signal that the "disposable" phase is over. That's when you should actually go back and define a proper record or class. Use anonymous types for local transformations—like filtering a list or grouping data for a quick loop—and stick to named types for your API contracts and business logic.
📋 Practical Task
Building a Simplified Product Catalog Projection
You have a list of Product objects, each containing a Name, Description, WholesalePrice, RetailPrice, and Sku. For a public-facing catalog page, you must not expose the WholesalePrice or the Sku.
Your Task:
- Create a list of
Productobjects (you can use a simple class for this). - Use a LINQ
.Select()statement to project these products into a collection of anonymous types. - The anonymous type should only contain the
Nameand theRetailPrice. - Iterate through the resulting collection and print the name and price to the console.
There are no comments for now.