如何在C#中使用Linq或Lambda对嵌套集合List C进行分页?
Alright, let's work through this nested pagination problem in C#. The tricky part here is dealing with the layered collections (A → B → C), but the solution boils down to first flattening all your C elements into a single sequence, then applying standard LINQ pagination on that flattened list. Let's break this down with concrete examples.
First, let's make sure we're on the same page with the class structure you described. Here's a simplified version:
public class A { public List<B> ListB { get; set; } } public class B { public List<C> ListC { get; set; } } public class C { // Add your actual properties here; this is just an example public int Id { get; set; } public string Details { get; set; } }
The key to pagination here is to first collapse all the nested List<C> instances into one flat collection of C objects. We use LINQ's SelectMany for this—it's perfect for drilling down through nested collections.
- If you have a single
Aobject:var allCs = myAInstance.ListB.SelectMany(b => b.ListC); - If you have a
List<A>(the main collection):var allCs = mainListOfA.SelectMany(a => a.ListB.SelectMany(b => b.ListC));
Once you have the flat collection, standard pagination is straightforward using Skip() and Take(). Remember:
Skip((pageNumber - 1) * pageSize)skips all items from previous pages (we subtract 1 because pages usually start at 1, not 0).Take(pageSize)grabs only the items for the current page.
Here's a full example with sample data:
// Setup sample data to test with var mainList = new List<A> { new A { ListB = new List<B> { new B { ListC = Enumerable.Range(1,4).Select(i => new C { Id = i, Details = $"Item {i}" }).ToList() }, new B { ListC = Enumerable.Range(5,10).Select(i => new C { Id = i, Details = $"Item {i}" }).ToList() }, new B { ListC = Enumerable.Range(15,35).Select(i => new C { Id = i, Details = $"Item {i}" }).ToList() } } } }; // Pagination parameters int targetPage = 2; // We want the 2nd page int itemsPerPage = 10; // Flatten, sort, and paginate var paginatedItems = mainList .SelectMany(a => a.ListB.SelectMany(b => b.ListC ?? Enumerable.Empty<C>())) // Handle null ListC safely .OrderBy(c => c.Id) // ALWAYS sort before pagination! Unordered collections give inconsistent results .Skip((targetPage - 1) * itemsPerPage) .Take(itemsPerPage) .ToList(); // Print results to verify foreach (var item in paginatedItems) { Console.WriteLine($"C Id: {item.Id}, Details: {item.Details}"); }
- Never skip sorting: If you don't sort before pagination, the order of items can change between requests, leading to duplicate or missing items in pages. Always add an
OrderBy()(orOrderByDescending()) beforeSkip(). - Handle null collections: If any
ListBorListCcould be null, add a null check likeb.ListC ?? Enumerable.Empty<C>()to avoidNullReferenceException. - Calculate total pages: If you need to show total pages to users, first get the total count of flattened items:
var totalItems = mainList.SelectMany(a => a.ListB.SelectMany(b => b.ListC ?? Enumerable.Empty<C>())).Count(); int totalPages = (int)Math.Ceiling(totalItems / (double)itemsPerPage);
This approach works regardless of how many B elements you have or how long each ListC is—it just treats all C items as a single pool for pagination.
内容的提问来源于stack exchange,提问作者Faseeh Haris

