Lưu nhiều List kiểu khác nhau vào một List chung trong C#
Vấn đề
C# là strongly-typed. List<T> chỉ chứa một kiểu T. Để lưu nhiều list kiểu khác nhau, cần một kiểu chung (common base).
Giải pháp 1: List<List<object>> (Đơn giản nhất)
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// List chứa các List
Giải pháp 2: Interface/Base Class chung (Type-safe hơn)
// Base interface
public interface IEntity
{
int Id { get; }
string DisplayName { get; }
}
public class User : IEntity
{
public int Id { get; set; }
public string Username { get; set; }
public string DisplayName => Username;
}
public class Product : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string DisplayName => Name;
}
// Sử dụng
var entities = new List>();
var users = new List
{
new User { Id = 1, Username = "john" },
new User { Id = 2, Username = "jane" }
};
var products = new List
{
new Product { Id = 100, Name = "Laptop" },
new Product { Id = 200, Name = "Mouse" }
};
entities.Add(users);
entities.Add(products);
// Type-safe access
foreach (var list in entities)
{
foreach (var entity in list)
{
Console.WriteLine($"ID: {entity.Id}, Name: {entity.DisplayName}");
}
}
Giải pháp 3: Tuple/List of Tuples (C# 7+)
// Tuple với named elements
var data = new List<(string Type, List Items)>
{
("Integers", new List { 1, 2, 3 }),
("Strings", new List { "A", "B", "C" }),
("Mixed", new List { 1, "Two", 3.0 })
};
foreach (var (type, items) in data)
{
Console.WriteLine($"--- {type} ---");
foreach (var item in items) Console.WriteLine(item);
}
Giải pháp 4: Dictionary với Key phân loại
// Dictionary> - group by type
var dict = new Dictionary>();
void Add(List list) where T : class
{
dict[typeof(T)] = list.Cast().ToList();
}
Add(new List { 1, 2, 3 });
Add(new List { "A", "B" });
// Truy xuất
if (dict.TryGetValue(typeof(int), out var ints))
{
foreach (var i in ints) Console.WriteLine(i);
}
Giải pháp 5: Pattern Matching khi đọc (C# 7+)
var lists = new List>
{
new List { 1, 2, 3 },
new List { "A", "B" },
new List { 1.5, 2.5 }
};
foreach (var list in lists)
{
foreach (var item in list)
{
switch (item)
{
case int i: Console.WriteLine($"Int: {i}"); break;
case string s: Console.WriteLine($"String: {s}"); break;
case double d: Console.WriteLine($"Double: {d}"); break;
default: Console.WriteLine($"Other: {item}"); break;
}
}
}
So sánh các giải pháp
Giải pháp
Type Safety
Performance
Phức tạp
Use Case
List<List<object>>
Thấp (boxing/unboxing)
Trung bình
Thấp
Quick prototype, throwaway code
List<List<IInterface>>
Cao
Tốt
Trung bình
Domain model có interface chung
List<(Type, List)>
Trung bình
Tốt
Thấp
Cần metadata về loại list
Dictionary<Type, List>
Cao (key là Type)
Tốt
Trung bình
Tra cứu nhanh theo kiểu
⚠️ Lưu ý quan trọng
Boxing/Unboxing cost: Khi dùng object với value types (int, double, struct) → boxing alloc heap, unboxing copy back. Với dữ liệu lớn/high-frequency → dùng generic interface hoặc custom solution.
Alternative: Non-generic IList (Legacy)
// Non-generic IList - chỉ dùng cho legacy COM/interop
System.Collections.IList list = new ArrayList();
list.Add(1);
list.Add("string");
// Không type-safe, boxing mọi value type - KHÔNG KHUYẾN NGHỊ