Bird
Raised Fist0
C Sharp (C#)programming~15 mins

LINQ with custom objects in C Sharp (C#) - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - LINQ with custom objects
What is it?
LINQ (Language Integrated Query) lets you ask questions about collections of data in a simple way. When you use LINQ with custom objects, you can filter, sort, and group your own data types easily. This means you can work with lists of your own classes just like you would with simple data like numbers or strings. It makes handling complex data clearer and faster.
Why it matters
Without LINQ, working with collections of custom objects would require writing lots of loops and conditions, which can be slow and error-prone. LINQ simplifies this by letting you write clear, readable queries that the computer understands directly. This saves time, reduces bugs, and helps you focus on what you want to do with your data, not how to do it.
Where it fits
Before learning LINQ with custom objects, you should understand basic C# classes and collections like lists. After mastering this, you can explore advanced LINQ features like joins, grouping, and query syntax versus method syntax. This knowledge also prepares you for working with databases using LINQ to SQL or Entity Framework.
Mental Model
Core Idea
LINQ lets you ask questions about your own objects as if they were simple lists, making complex data easy to explore and manipulate.
Think of it like...
Imagine you have a box of different toys (custom objects). LINQ is like a magic magnifying glass that helps you quickly find all the red cars or sort the toys by size without digging through the box by hand.
Custom Objects Collection
┌─────────────────────────┐
│ List<Person>            │
│ ┌─────────┐ ┌─────────┐ │
│ │ Person1 │ │ Person2 │ │
│ └─────────┘ └─────────┘ │
└─────────┬───────────────┘
          │
          ▼
     LINQ Query
┌─────────────────────────┐
│ people.Where(p => p.Age > 20) │
└─────────┬───────────────┘
          │
          ▼
Filtered List
┌─────────┐
│ Person2 │
└─────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Custom Objects
🤔
Concept: Learn what custom objects are and how to create them in C#.
A custom object is a class you define with properties and methods. For example, a Person class with Name and Age properties: public class Person { public string Name { get; set; } public int Age { get; set; } } You can create a list of Person objects to hold multiple people.
Result
You can create and store multiple Person objects in a list.
Knowing how to define and use custom objects is the foundation for querying them with LINQ.
2
FoundationBasic LINQ Queries on Lists
🤔
Concept: Learn how to write simple LINQ queries on lists of basic data types.
LINQ lets you filter and select data easily. For example, filtering numbers greater than 5: var numbers = new List {1, 6, 3, 8}; var filtered = numbers.Where(n => n > 5); This returns 6 and 8.
Result
You get a filtered list of numbers matching the condition.
Understanding LINQ on simple lists prepares you to apply the same ideas to custom objects.
3
IntermediateApplying LINQ to Custom Objects
🤔Before reading on: do you think LINQ queries on custom objects use the same syntax as with simple types? Commit to your answer.
Concept: LINQ works the same way on custom objects by using their properties in queries.
Given a list of Person objects: var people = new List { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 18 }, new Person { Name = "Charlie", Age = 25 } }; You can filter adults: var adults = people.Where(p => p.Age >= 21); This returns Alice and Charlie.
Result
You get a filtered list of Person objects matching the age condition.
Knowing that LINQ queries use object properties lets you write powerful, readable filters on your data.
4
IntermediateSorting and Selecting with LINQ
🤔Before reading on: do you think you can sort custom objects by any property using LINQ? Commit to your answer.
Concept: LINQ can sort and select specific properties from custom objects easily.
You can sort people by age: var sorted = people.OrderBy(p => p.Age); Or select just their names: var names = people.Select(p => p.Name); This returns a list of names.
Result
You get sorted lists or lists of specific properties from your objects.
Understanding sorting and projection with LINQ helps you shape data exactly how you want it.
5
IntermediateCombining Filters and Projections
🤔Before reading on: do you think you can chain multiple LINQ methods to filter and then select data? Commit to your answer.
Concept: LINQ methods can be combined to perform complex queries in a clear way.
Example: get names of adults only: var adultNames = people.Where(p => p.Age >= 21).Select(p => p.Name); This filters adults and then selects their names.
Result
You get a list of names of people who are adults.
Knowing how to chain LINQ methods unlocks powerful data querying with minimal code.
6
AdvancedUsing LINQ with Custom Comparers
🤔Before reading on: do you think LINQ can sort objects using custom rules beyond simple property values? Commit to your answer.
Concept: You can define custom comparison logic to sort or compare objects in LINQ queries.
Sometimes you want to sort by multiple properties or special rules. You can create a class implementing IComparer: class PersonAgeNameComparer : IComparer { public int Compare(Person x, Person y) { int ageCompare = x.Age.CompareTo(y.Age); if (ageCompare != 0) return ageCompare; return x.Name.CompareTo(y.Name); } } Then use: var sorted = people.OrderBy(p => p, new PersonAgeNameComparer());
Result
You get a list sorted first by age, then by name if ages are equal.
Understanding custom comparers lets you control sorting beyond simple property values, essential for real-world data.
7
ExpertPerformance and Deferred Execution in LINQ
🤔Before reading on: do you think LINQ queries run immediately or only when you use the results? Commit to your answer.
Concept: LINQ queries use deferred execution, meaning they run only when you access the data, affecting performance and behavior.
When you write a LINQ query, it doesn't run right away. For example: var query = people.Where(p => p.Age > 20); No filtering happens yet. Only when you loop or convert to a list: var list = query.ToList(); The filtering runs then. This means if the original list changes before execution, results change too.
Result
LINQ queries are efficient but can produce different results if data changes before execution.
Knowing deferred execution helps avoid bugs and optimize performance by controlling when queries run.
Under the Hood
LINQ queries are translated into method calls on IEnumerable or IQueryable interfaces. For collections like List, LINQ uses extension methods that return iterators. These iterators do not process data immediately but store the query logic. When you iterate over the query, the logic runs step-by-step, fetching and filtering items on demand. This is called deferred execution. For databases, LINQ expressions are translated into SQL queries by providers.
Why designed this way?
Deferred execution was chosen to improve performance and flexibility. It allows chaining queries without running them multiple times and lets data change before execution. Also, it fits well with both in-memory collections and remote data sources like databases, making LINQ a unified querying tool.
LINQ Query Flow
┌───────────────┐
│ Your Code     │
│ var query =   │
│ people.Where()│
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ LINQ Methods  │
│ (Extension)   │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Iterator      │
│ (Deferred)    │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Data Source   │
│ (List<Person>)│
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does LINQ immediately run queries when you write them? Commit to yes or no.
Common Belief:LINQ queries run as soon as you write them.
Tap to reveal reality
Reality:LINQ uses deferred execution, so queries run only when you access the results.
Why it matters:Assuming immediate execution can cause bugs when data changes after query creation but before execution.
Quick: Can LINQ only work with simple data types like int or string? Commit to yes or no.
Common Belief:LINQ only works with built-in data types, not custom objects.
Tap to reveal reality
Reality:LINQ works equally well with custom objects as long as you use their properties in queries.
Why it matters:Believing this limits your ability to write clean, powerful queries on your own data.
Quick: Does LINQ always create new lists when filtering? Commit to yes or no.
Common Belief:LINQ filtering always creates a new list immediately.
Tap to reveal reality
Reality:LINQ filtering returns an enumerable that runs when iterated; it does not create a new list unless you call ToList().
Why it matters:Misunderstanding this can lead to unexpected performance issues or bugs when modifying the original collection.
Quick: Can you sort custom objects in LINQ only by one property? Commit to yes or no.
Common Belief:You can only sort custom objects by one property at a time in LINQ.
Tap to reveal reality
Reality:You can sort by multiple properties using ThenBy or custom comparers.
Why it matters:Knowing this allows more precise sorting needed in real applications.
Expert Zone
1
LINQ queries on custom objects can be optimized by using compiled expressions to improve performance in repeated queries.
2
Deferred execution means side effects in property getters can cause unexpected results if not carefully managed.
3
Using anonymous types in Select projections can simplify data shaping but requires understanding of scope and type inference.
When NOT to use
LINQ is not ideal for very large datasets where streaming or manual optimized loops are needed for performance. Also, for complex multi-step transformations, specialized libraries or manual code may be clearer. For real-time or low-latency systems, LINQ's deferred execution and allocations might add overhead.
Production Patterns
In production, LINQ with custom objects is used for filtering user data, sorting product lists, and projecting data for UI display. It is common to combine LINQ with async data sources, caching results, and using custom comparers for business rules. LINQ expressions are also translated to database queries in ORMs like Entity Framework.
Connections
Functional Programming
LINQ builds on functional programming ideas like map, filter, and reduce.
Understanding functional programming helps grasp LINQ's chaining and immutability concepts.
Database Query Languages (SQL)
LINQ syntax and concepts parallel SQL queries for filtering and sorting data.
Knowing SQL helps understand LINQ's purpose and how it translates queries to databases.
Data Filtering in Everyday Life
Filtering a list of custom objects with LINQ is like sorting mail by address or filtering photos by date.
Recognizing this connection helps see LINQ as a tool for organizing and finding information efficiently.
Common Pitfalls
#1Assuming LINQ queries run immediately and expecting results before iteration.
Wrong approach:var adults = people.Where(p => p.Age > 20); Console.WriteLine(adults.Count()); // expecting immediate count
Correct approach:var adults = people.Where(p => p.Age > 20).ToList(); Console.WriteLine(adults.Count);
Root cause:Misunderstanding deferred execution causes confusion about when queries run.
#2Trying to sort custom objects without specifying a property or comparer.
Wrong approach:var sorted = people.OrderBy(p => p);
Correct approach:var sorted = people.OrderBy(p => p.Age);
Root cause:Not knowing LINQ needs a key selector or comparer to sort objects.
#3Modifying the collection while iterating over a LINQ query.
Wrong approach:foreach(var p in people.Where(p => p.Age > 20)) { people.Remove(p); }
Correct approach:var toRemove = people.Where(p => p.Age > 20).ToList(); foreach(var p in toRemove) { people.Remove(p); }
Root cause:Not realizing LINQ queries are linked to the original collection and modifying it during iteration causes errors.
Key Takeaways
LINQ lets you write clear, readable queries on your own custom objects using their properties.
LINQ queries use deferred execution, meaning they run only when you access the results, which affects behavior and performance.
You can chain LINQ methods to filter, sort, and select data in powerful ways with minimal code.
Custom comparers and multi-property sorting extend LINQ's flexibility for real-world data needs.
Understanding LINQ's internal mechanics and common pitfalls helps you write efficient and bug-free code.

Practice

(1/5)
1. What does LINQ primarily help you do with custom objects in C#?
easy
A. Create new classes automatically
B. Compile code faster
C. Filter, sort, and select data easily
D. Manage memory manually

Solution

  1. Step 1: Understand LINQ's purpose

    LINQ is designed to query collections like lists of objects easily.
  2. Step 2: Identify LINQ's main features

    It helps filter, sort, and select data without manual loops.
  3. Final Answer:

    Filter, sort, and select data easily -> Option C
  4. Quick Check:

    LINQ = Filter, sort, select [OK]
Hint: Remember LINQ is for querying data collections [OK]
Common Mistakes:
  • Thinking LINQ creates classes
  • Confusing LINQ with compilation
  • Assuming LINQ manages memory
2. Which of the following is the correct syntax to select all names from a list of Person objects using LINQ?
easy
A. var names = people.Select(p => p.Name());
B. var names = people.Select(p.Name);
C. var names = people.Select(p => p);
D. var names = people.Select(p => p.Name);

Solution

  1. Step 1: Understand Select syntax

    Select expects a lambda expression to pick a property, like p => p.Name.
  2. Step 2: Check each option

    var names = people.Select(p => p.Name); uses correct lambda syntax. var names = people.Select(p.Name); misses lambda. var names = people.Select(p => p); selects whole object. var names = people.Select(p => p.Name()); wrongly calls Name as method.
  3. Final Answer:

    var names = people.Select(p => p.Name); -> Option D
  4. Quick Check:

    Select needs lambda with property [OK]
Hint: Use lambda syntax p => p.Property for Select [OK]
Common Mistakes:
  • Omitting lambda arrow =>
  • Calling property as method
  • Selecting whole object instead of property
3. Given the class Person { public string Name; public int Age; } and list people with three persons: Alice(30), Bob(25), and Carol(35), what does this LINQ query return?
var result = people.Where(p => p.Age > 28).Select(p => p.Name).ToList();
medium
A. ["Alice", "Carol"]
B. ["Bob"]
C. ["Alice", "Bob", "Carol"]
D. Empty list

Solution

  1. Step 1: Filter people older than 28

    Alice is 30 (yes), Bob is 25 (no), Carol is 35 (yes).
  2. Step 2: Select their names

    Names selected are "Alice" and "Carol".
  3. Final Answer:

    ["Alice", "Carol"] -> Option A
  4. Quick Check:

    Age > 28 filters Alice and Carol [OK]
Hint: Filter first, then select property [OK]
Common Mistakes:
  • Including Bob who is younger
  • Selecting whole object instead of names
  • Confusing > with <
4. What is wrong with this LINQ query?
var adults = people.Where(p => p.Age >= 18).Select(p => p.Name);
foreach(var name in adults) Console.WriteLine(name);
medium
A. The query is correct and will print all names of adults
B. The lambda expression syntax is incorrect
C. The query is missing ToList() or ToArray(), so it won't compile
D. The Where clause should be after Select

Solution

  1. Step 1: Check LINQ query syntax

    Where and Select are used correctly with proper lambda syntax.
  2. Step 2: Check foreach usage

    LINQ returns IEnumerable<string>, which foreach can iterate without ToList().
  3. Final Answer:

    The query is correct and will print all names of adults -> Option A
  4. Quick Check:

    IEnumerable works with foreach directly [OK]
Hint: IEnumerable can be iterated without ToList() [OK]
Common Mistakes:
  • Thinking ToList() is mandatory before foreach
  • Misplacing Where and Select order
  • Incorrect lambda syntax
5. You have a list of Product objects with properties Name (string) and Price (decimal). How do you create a dictionary with product names as keys and prices as values, but only include products costing more than 50 using LINQ?
hard
A. products.ToDictionary(p => p.Name, p => p.Price).Where(p => p.Value > 50);
B. products.Where(p => p.Price > 50).ToDictionary(p => p.Name, p => p.Price);
C. products.Select(p => new {p.Name, p.Price > 50}).ToDictionary(p => p.Name, p => p.Price);
D. products.Where(p => p.Price > 50).Select(p => p.Name).ToDictionary();

Solution

  1. Step 1: Filter products with price > 50

    Use Where to keep only products costing more than 50.
  2. Step 2: Convert filtered list to dictionary

    Use ToDictionary with key selector p.Name and value selector p.Price.
  3. Final Answer:

    products.Where(p => p.Price > 50).ToDictionary(p => p.Name, p => p.Price); -> Option B
  4. Quick Check:

    Filter then ToDictionary with key and value selectors [OK]
Hint: Filter first, then use ToDictionary with key and value [OK]
Common Mistakes:
  • Trying to filter after ToDictionary (invalid)
  • Selecting anonymous types instead of original objects
  • Calling ToDictionary without key/value selectors