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
62: Object and Collection Initializers
I've spent a lot of time reviewing code from developers who are transitioning into C#, and there is one habit I see constantly: the "instantiate then assign" pattern. It isn't wrong—the code works perfectly—but it's visually noisy. When you're staring at a file with hundreds of lines of configuration or data setup, that noise starts to obscure the actual logic of your program.
The Verbose Way of Setting State
Imagine we're building a simple system to track a library's inventory. We have a Book class with a few properties. In the naive approach, you'd probably write something like this:
Book myBook = new Book();
myBook.Title = "The Pragmatic Programmer";
myBook.Author = "Andrew Hunt";
myBook.Isbn = "978-0135957059";
myBook.YearPublished = 1999;
It's functional, but it's tedious. You're repeating the variable name myBook over and over again. From a compiler's perspective, this is fine, but for us humans, it's an eyesore. We can see at a glance that this is just a setup block, yet it takes up five lines of vertical space. In a real project, you might be doing this for ten different objects, and suddenly your method is 50 lines of boilerplate before you even get to the actual business logic.
Streamlining with Object Initializers
This is where object initializers come in. They allow you to assign values to any accessible fields or properties of an object at the moment of creation, all within a single expression. Here is how I would write that same block:
var myBook = new Book
{
Title = "The Pragmatic Programmer",
Author = "Andrew Hunt",
Isbn = "978-0135957059",
YearPublished = 1999
};
Notice that we didn't have to repeat the variable name. The curly braces effectively tell C#, "Create this object, and before you hand it back to me, set these specific properties." It's cleaner, and it groups the initialization into one logical unit. One thing to keep in mind: you can still use a constructor if you need to. If Book had a constructor that required a Category, you'd put the arguments in parentheses first, and then the initializer braces immediately after.
Cleaning Up Collection Setup
The same "noise" problem happens with collections. If you're filling a List with some starting data, the old-school way involves a lot of .Add() calls:
List<Book> library = new List<Book>();
library.Add(new Book { Title = "Clean Code" });
library.Add(new Book { Title = "Refactoring" });
library.Add(new Book { Title = "Design Patterns" });
That's a lot of typing for very little value. C# provides collection initializers that let you treat the list like a literal array during creation. I prefer this approach because it makes the collection look like the data it contains, rather than a series of commands to modify a list.
var library = new List<Book>
{
new Book { Title = "Clean Code" },
new Book { Title = "Refactoring" },
new Book { Title = "Design Patterns" }
};
When This Doesn't Work
I should warn you that initializers aren't a magic bullet for every scenario. For an object initializer to work, the properties must have a set accessor (or an init accessor in newer C# versions). If a property is read-only and only set via a constructor, the initializer will throw a compiler error. Similarly, collection initializers rely on the collection implementing IEnumerable and having an Add method. If you're working with a custom collection that doesn't follow those rules, you'll have to go back to the manual .Add() approach. It's a rare occurrence in modern C#, but it's something to watch for when you're building your own complex data structures.
📋 Practical Task
Refactoring the Movie Theater Ticket System
You have been handed a piece of legacy code for a movie theater system. The current code is functional but incredibly verbose, using the "instantiate then assign" pattern for both the Movie objects and the Screening list. Your task is to refactor this code to use Object Initializers and Collection Initializers to make it concise and readable.
Starting Code:
public class Movie {
public string Title { get; set; }
public int DurationMinutes { get; set; }
public string Genre { get; set; }
}
public class Program {
public static void Main() {
Movie m1 = new Movie();
m1.Title = "Inception";
m1.DurationMinutes = 148;
m1.Genre = "Sci-Fi";
Movie m2 = new Movie();
m2.Title = "The Godfather";
m2.DurationMinutes = 175;
m2.Genre = "Crime";
List<Movie> schedule = new List<Movie>();
schedule.Add(m1);
schedule.Add(m2);
}
}
Requirements:
- Rewrite the
Mainmethod so that theschedulelist is initialized using a collection initializer. - Inside that collection initializer, instantiate the
Movieobjects using object initializers. - The final result should eliminate the need for the temporary
m1andm2variables entirely.
There are no comments for now.