Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Use when lINQ query and method syntax, deferred execution, and performance optimization. Use when querying collections in C#.
allowed-tools
["Bash","Read","Write","Edit"]
C# LINQ
Master Language Integrated Query (LINQ) for querying and transforming data in C#.
This skill covers query syntax, method syntax, deferred execution, performance
optimization, and advanced LINQ patterns from C# 8-12.
LINQ Query Syntax vs Method Syntax
LINQ supports two syntaxes: query syntax (SQL-like) and method syntax (fluent).
Both compile to the same code.
Query Syntax
var students = new List<Student>
{
new Student { Name = "Alice", Grade = 85, Age = 20 },
new Student { Name = "Bob", Grade = 92, Age = 21 },
new Student { Name = "Charlie", Grade = 78, Age = 20 }
};
// Query syntax - SQL-likevar topStudents = student students
student.Grade >=
student.Grade
{ student.Name, student.Grade };
( student topStudents)
{
Console.WriteLine();
}
from
in
where
80
orderby
descending
select
new
foreach
var
in
$"{student.Name}: {student.Grade}"
Method Syntax
// Method syntax - fluent APIvar topStudents = students
.Where(s => s.Grade >= 80)
.OrderByDescending(s => s.Grade)
.Select(s => new { s.Name, s.Grade });
// Method syntax is more flexible for complex queriesvar result = students
.Where(s => s.Age >= 20)
.GroupBy(s => s.Age)
.Select(g => new
{
Age = g.Key,
AverageGrade = g.Average(s => s.Grade),
Count = g.Count()
})
.OrderBy(x => x.Age);
When to Use Each Syntax
// Query syntax better for joinsvar query1 = from student in students
join course in courses on student.Id equals course.StudentId
where course.Grade > 80selectnew { student.Name, course.Title };
// Method syntax better for chaining and complex logicvar query2 = students
.Where(s => s.Age >= 20)
.SelectMany(s => s.Courses)
.Where(c => c.Grade > 80)
.Distinct()
.Take(10);
// Mixed approachvar query3 = (from s in students
where s.Age >= 20select s)
.Take(10)
.ToList(); // Force execution
Deferred Execution
LINQ queries use deferred execution - they don't execute until enumerated.
Understanding Deferred Execution
var numbers = new List<int> { 1, 2, 3, 4, 5 };
// Query is defined but NOT executedvar query = numbers.Where(n => n > 2);
// Add more numbers
numbers.Add(6);
numbers.Add(7);
// Query executes NOW when enumeratedforeach (var num in query) // Gets: 3, 4, 5, 6, 7
{
Console.WriteLine(num);
}
// Query executes AGAIN (sees current state)var count = query.Count(); // 5// Force immediate execution with ToList(), ToArray(), etc.var snapshot = numbers.Where(n => n > 2).ToList();
numbers.Add(8);
Console.WriteLine(snapshot.Count); // Still 5, not 6
Deferred vs Immediate Execution
publicclassDeferredExecutionExample
{
publicvoidDemonstrate()
{
var data = new List<int> { 1, 2, 3, 4, 5 };
// Deferred - query not executed yetvar deferred = data.Where(x => x > 2);
// Immediate - query executed nowvar immediate = data.Where(x => x > 2).ToList();
// Modify source
data.Add(6);
Console.WriteLine(deferred.Count()); // 4 (includes 6)
Console.WriteLine(immediate.Count()); // 3 (snapshot before 6 was added)
}
// Dangerous: query is rebuilt each iterationpublicvoidDangerousPattern()
{
var data = GetData(); // Expensive// ❌ BAD - GetData() called multiple timesforeach (var item inGetData().Where(x => x.IsActive))
{
Process(item);
}
// ✅ GOOD - GetData() called oncevar items = GetData().Where(x => x.IsActive).ToList();
foreach (var item in items)
{
Process(item);
}
}
}
IEnumerable vs IQueryable
IEnumerable executes in memory (LINQ to Objects). IQueryable translates to
expression trees for remote execution (LINQ to SQL, EF).
IEnumerable<T> - In-Memory
publicclassInMemoryQueries
{
publicvoidQueryInMemory()
{
var products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 999 },
new Product { Id = 2, Name = "Mouse", Price = 25 },
new Product { Id = 3, Name = "Keyboard", Price = 75 }
};
// IEnumerable - executes in memory
IEnumerable<Product> query = products
.Where(p => p.Price > 50)
.OrderBy(p => p.Name);
// All filtering happens in C# codeforeach (var product in query)
{
Console.WriteLine($"{product.Name}: ${product.Price}");
}
}
}
IQueryable<T> - Expression Trees
publicclassQueryableExamples
{
privatereadonly DbContext _context;
// IQueryable - translates to SQLpublicasync Task<List<Product>> GetExpensiveProductsAsync()
{
// Query builds expression tree
IQueryable<Product> query = _context.Products
.Where(p => p.Price > 50)
.OrderBy(p => p.Name);
// SQL generated and executed herereturnawait query.ToListAsync();
// SQL: SELECT * FROM Products WHERE Price > 50 ORDER BY Name
}
// Composable queriespublic IQueryable<Product> GetActiveProducts()
{
return _context.Products.Where(p => p.IsActive);
}
publicasync Task<List<Product>> GetExpensiveActiveProductsAsync()
{
// Compose queries - still generates single SQLvar products = await GetActiveProducts()
.Where(p => p.Price > 100)
.ToListAsync();
// SQL: SELECT * FROM Products WHERE IsActive = 1 AND Price > 100return products;
}
}
Mixing IEnumerable and IQueryable
publicclassMixingQueries
{
privatereadonly DbContext _context;
publicasync Task<List<ProductDto>> GetProductsDangerousAsync()
{
// ❌ BAD - ToList() brings ALL products to memory firstvar products = await _context.Products.ToListAsync();
// Then filters in memory (inefficient)return products
.Where(p => p.Price > 100) // In memory
.Select(p => new ProductDto { Name = p.Name })
.ToList();
}
publicasync Task<List<ProductDto>> GetProductsEfficientAsync()
{
// ✅ GOOD - everything in SQLreturnawait _context.Products
.Where(p => p.Price > 100) // In SQL
.Select(p => new ProductDto { Name = p.Name }) // In SQL
.ToListAsync(); // Execute once
}
publicasync Task<List<Product>> ComplexFilterAsync()
{
// ✅ GOOD - SQL where possible, memory when necessaryreturnawait _context.Products
.Where(p => p.Price > 50) // SQL
.ToListAsync() // Execute SQL
.ContinueWith(t => t.Result
.Where(p => ComplexInMemoryCheck(p)) // C# predicate
.ToList()
);
}
privateboolComplexInMemoryCheck(Product product)
{
// Logic that can't be translated to SQLreturn product.Name.Split(' ').Length > 2;
}
}
var customers = GetCustomers();
var orders = GetOrders();
// Inner joinvar customerOrders = from c in customers
join o in orders on c.Id equals o.CustomerId
selectnew { c.Name, o.OrderDate, o.Total };
// Method syntaxvar customerOrders2 = customers.Join(
orders,
c => c.Id,
o => o.CustomerId,
(c, o) => new { c.Name, o.OrderDate, o.Total }
);
// Left outer joinvar leftJoin = from c in customers
join o in orders on c.Id equals o.CustomerId into customerOrders
from co in customerOrders.DefaultIfEmpty()
selectnew
{
Customer = c.Name,
OrderTotal = co?.Total ?? 0
};
// Multiple joinsvar fullData = from c in customers
join o in orders on c.Id equals o.CustomerId
join od in orderDetails on o.Id equals od.OrderId
selectnew { c.Name, o.OrderDate, od.Product };
Aggregation Operations
Basic Aggregations
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Countint count = numbers.Count();
int evenCount = numbers.Count(n => n % 2 == 0);
// Sumint sum = numbers.Sum();
decimal totalPrice = products.Sum(p => p.Price);
// Averagedouble avg = numbers.Average();
double avgGrade = students.Average(s => s.Grade);
// Min/Maxint min = numbers.Min();
int max = numbers.Max();
var cheapest = products.MinBy(p => p.Price); // C# 9+var mostExpensive = products.MaxBy(p => p.Price); // C# 9+// Any/Allbool hasEvens = numbers.Any(n => n % 2 == 0);
bool allPositive = numbers.All(n => n > 0);
// First/Last/Singlevar first = numbers.First();
var firstEven = numbers.First(n => n % 2 == 0);
var firstOrNull = numbers.FirstOrDefault(n => n > 100); // 0var single = numbers.Single(n => n == 5);
var last = numbers.Last();
Advanced Aggregations
publicclassAggregationExamples
{
publicvoidAdvancedAggregates()
{
var sales = GetSales();
// Aggregate - custom accumulatorvar total = sales.Aggregate(0m, (acc, sale) => acc + sale.Amount);
// Complex aggregationvar stats = sales.Aggregate(
new { Sum = 0m, Count = 0 },
(acc, sale) => new
{
Sum = acc.Sum + sale.Amount,
Count = acc.Count + 1
},
acc => new
{
acc.Sum,
acc.Count,
Average = acc.Sum / acc.Count
}
);
// Grouped aggregationsvar categorySummary = sales
.GroupBy(s => s.Category)
.Select(g => new
{
Category = g.Key,
Count = g.Count(),
Total = g.Sum(s => s.Amount),
Average = g.Average(s => s.Amount),
Min = g.Min(s => s.Amount),
Max = g.Max(s => s.Amount)
});
}
}
Set Operations
Distinct, Union, Intersect, Except
var list1 = new[] { 1, 2, 3, 4, 5 };
var list2 = new[] { 4, 5, 6, 7, 8 };
// Distinct - remove duplicatesvar unique = new[] { 1, 2, 2, 3, 3, 3 }.Distinct(); // 1, 2, 3// DistinctBy - C# 9+var customers = GetCustomers();
var uniqueByEmail = customers.DistinctBy(c => c.Email);
// Union - combine and remove duplicatesvar union = list1.Union(list2); // 1, 2, 3, 4, 5, 6, 7, 8// Concat - combine without removing duplicatesvar concatenated = list1.Concat(list2); // 1, 2, 3, 4, 5, 4, 5, 6, 7, 8// Intersect - common elementsvar intersection = list1.Intersect(list2); // 4, 5// Except - elements in first but not secondvar difference = list1.Except(list2); // 1, 2, 3// Set operations with custom comparervar products1 = GetProducts();
var products2 = GetMoreProducts();
var uniqueProducts = products1.Union(products2, new ProductComparer());