# 2026'da İleri Düzey C# LINQ: Operatörler, Performans ve Mülakat Soruları > İleri düzey LINQ operatörlerini, ertelenmiş yürütmeyi ve performans optimizasyonunu öğrenin. GroupBy, SelectMany, sorgu optimizasyonu ve .NET geliştiricileri için yaygın mülakat sorularını kapsar. - Published: 2026-08-23 - Updated: 2026-08-23 - Author: Anthony Fillion-Maillet - Tags: C#, LINQ, .NET, Performans, Mülakat - Reading time: 12 min --- İleri düzey C# LINQ operatörleri, deneyimli .NET geliştiricilerini yeni başlayanlardan ayırır. `Where` ve `Select` temel filtrelemeyi hallederken, gerçek dünya projeleri `GroupBy`, `SelectMany`, ertelenmiş yürütme kalıpları ve performans bilinçli sorgu kompozisyonunda ustalık gerektirir. > **Mülakat Sinyali** > > Mülakatçılar sıklıkla adaylardan ertelenmiş ve anında yürütme arasındaki farkı açıklamalarını veya yavaş bir LINQ sorgusunu optimize etmelerini ister. Kaputun altında neler olduğunu anlamak, kıdemli adayları sadece sözdizimini ezberleyenlerden ayırır. ## LINQ'da Ertelenmiş Yürütmeyi Anlamak LINQ sorguları bildirildiğinde yürütülmez. Yürütme, sonuç numaralandırıldığında gerçekleşir, genellikle `foreach`, `ToList()` veya `ToArray()` aracılığıyla. Ertelenmiş yürütme (deferred execution) olarak adlandırılan bu davranış, tekrarlanan veritabanı veya koleksiyon taramaları olmadan sorgu kompozisyonunu mümkün kılar. ```csharp // DeferredExecutionDemo.cs var numbers = new List { 1, 2, 3, 4, 5 }; // Query is defined but not executed var query = numbers.Where(n => n > 2); // Adding an element after query definition numbers.Add(6); // Execution happens here, includes 6 foreach (var n in query) { Console.WriteLine(n); // Output: 3, 4, 5, 6 } ``` Sorgu, içeriğini değil `numbers` referansını yakalar. `foreach` yinelediğinde, güncellenmiş koleksiyonu görür. Bu kalıp, dinamik sorguları aşamalı olarak oluşturmak için kullanışlıdır, ancak geliştiriciler anlık görüntü davranışı beklediğinde hatalara neden olur. Anında yürütmeyi zorlamak için `ToList()`, `ToArray()` veya `ToDictionary()` çağrılmalıdır. Bu yöntemler kaynağı bir kez numaralandırır ve sonuçları önbelleğe alır. ## GroupBy: Temel Gruplama Ötesinde `GroupBy`, düz koleksiyonları hiyerarşik yapılara dönüştürür. Operatör dört parametreye kadar kabul eder: anahtar seçici, eleman seçici, sonuç seçici ve özel karşılaştırıcı. ```csharp // OrderAnalytics.cs public record Order(int Id, string Customer, decimal Amount, DateTime Date); var orders = GetOrders(); // Group by customer with monthly breakdown var customerMonthlyTotals = orders .GroupBy( o => new { o.Customer, Month = new DateTime(o.Date.Year, o.Date.Month, 1) }, (key, group) => new { key.Customer, key.Month, Total = group.Sum(o => o.Amount), OrderCount = group.Count() }) .OrderBy(x => x.Customer) .ThenBy(x => x.Month); // Output: Customer "Acme" spent $12,500 across 8 orders in August 2026 ``` Bileşik anahtar hem müşteriye hem de aya göre gruplar. Sonuç seçici, ikinci bir `Select` geçişinden kaçınarak doğrudan analitik için hazır bir şekle projeksiyon yapar. > **Bellek Değerlendirmesi** > > `GroupBy` grupları oluşturmak için tüm kaynağı tamponlamalıdır. Büyük veri setleri veya akış senaryoları için EF Core ile veritabanı tarafında gruplamayı düşünün veya gruplandırılmış sonuca birden fazla kez erişilecekse `ToLookup` kullanın. ## SelectMany: İç İçe Koleksiyonları Düzleştirme `SelectMany`, bire-çok ilişkilerini tek bir diziye düzleştirir. Operatör, her elemanın sıfır veya daha fazla sonuç ürettiği senaryoları ele alır. ```csharp // ProductCatalog.cs public record Category(string Name, List Products); public record Product(string Name, decimal Price); var categories = GetCategories(); // Flatten all products with their category names var allProducts = categories .SelectMany( category => category.Products, (category, product) => new { CategoryName = category.Name, ProductName = product.Name, product.Price }); // Filter after flattening var expensiveProducts = allProducts .Where(p => p.Price > 100) .OrderByDescending(p => p.Price); ``` `SelectMany`'nin iki parametreli aşırı yüklemesi hem üst hem de alt elemanlara erişim sağlar, her iki seviyeden verileri birleştiren projeksiyonlara olanak tanır. Bu kalıp, iç içe `foreach` döngülerini bildirimsel bir yaklaşımla değiştirir. Sorgu sözdizimi, bazı geliştiricilerin karmaşık birleştirmeler için daha okunabilir bulduğu bir alternatif sunar: ```csharp // QuerySyntaxFlatten.cs var productsWithCategories = from category in categories from product in category.Products where product.Price > 100 select new { category.Name, product }; ``` Her ikisi de aynı `SelectMany` çağrısına derlenir. Takım kuralı ve sorgu karmaşıklığına göre seçim yapılmalıdır. ## LINQ Performansını Optimize Etme LINQ soyutlamaları maliyet taşır. Her zincirlenen operatör bir yineleyici nesnesi oluşturur ve lambda ifadeleri temsilci çağırma maliyetleri ekler. Saniyede binlerce eleman işleyen kritik yollar için bu maliyetler birikim yapar. ### Çoklu Numaralandırmalardan Kaçınma ```csharp // MultipleEnumerationProblem.cs IEnumerable GetExpensiveOrders(IEnumerable orders) { var filtered = orders.Where(o => o.Amount > 1000); // WARNING: Enumerates twice if orders is not materialized if (!filtered.Any()) return Enumerable.Empty(); return filtered.OrderBy(o => o.Date); } ``` `orders` bir veritabanı sorgusundan veya dosya akışından geliyorsa, bu kod kaynağı iki kez yürütür. Çoklu işlemlerden önce `ToList()` ile somutlaştırılmalıdır: ```csharp // FixedMultipleEnumeration.cs IEnumerable GetExpensiveOrders(IEnumerable orders) { var filtered = orders.Where(o => o.Amount > 1000).ToList(); if (filtered.Count == 0) return Enumerable.Empty(); return filtered.OrderBy(o => o.Date); } ``` ### Doğru Operatörü Seçme Bazı LINQ operatörlerinin belirli koleksiyon türleri için optimize edilmiş uygulamaları vardır: | İşlem | Yavaş Versiyon | Hızlı Versiyon | Notlar | |-----------|--------------|--------------|-------| | Sayım | `collection.Count()` | `collection.Count` | `ICollection` için özellik kullanın | | Eleman erişimi | `collection.ElementAt(5)` | `collection[5]` | `IList` için indeksleyici kullanın | | Varlık kontrolü | `collection.Count() > 0` | `collection.Any()` | `Any()` kısa devre yapar | | İlk eşleşme | `collection.Where(x).First()` | `collection.First(x)` | Tek geçiş vs. iki yineleyici | ## Aggregate: Özel İndirgeme İşlemleri `Aggregate`, bir birikimci fonksiyonu uygulayarak bir diziden tek bir sonuç oluşturur. `Sum`, `Max` ve `Average` yaygın durumları ele alırken, `Aggregate` özel indirgemeler sağlar. ```csharp // CustomAggregation.cs var transactions = new List { new("Deposit", 1000), new("Withdrawal", -200), new("Deposit", 500), new("Fee", -25) }; // Running balance with audit trail var balanceHistory = transactions.Aggregate( new List<(string Op, decimal Balance)>(), (history, tx) => { var previousBalance = history.Count > 0 ? history[^1].Balance : 0; history.Add((tx.Type, previousBalance + tx.Amount)); return history; }); // Output: [(Deposit, 1000), (Withdrawal, 800), (Deposit, 1300), (Fee, 1275)] ``` Üç parametreli aşırı yükleme, birikimci türü sonuç türünden farklı olduğunda kullanışlı olan bir başlangıç değeri ve son sonuç seçici ekler. ## LINQ to Objects vs. LINQ to Entities Bir sorgunun nerede yürütüldüğünü anlamak, performans karakteristiklerini belirler. LINQ to Objects, C# temsilcileriyle bellekte çalışır. LINQ to Entities (EF Core), ifadeleri SQL'e çevirir. ```csharp // EFCoreQueryOptimization.cs using var context = new AppDbContext(); // BAD: Loads all orders, filters in memory var badQuery = context.Orders .ToList() .Where(o => o.Amount > 1000); // GOOD: Filters in database, loads only matching rows var goodQuery = context.Orders .Where(o => o.Amount > 1000) .ToList(); ``` `ToList()`'in yerleşimi her şeyi değiştirir. Kötü örnekte, SQL Server binlerce satır döndürür, sonra C# çoğunu atar. İyi örnekte, `WHERE` cümlesi sunucu tarafında çalışır. Karmaşık projeksiyonlar için EF Core 9 (Ağustos 2026 itibarıyla güncel), ilişkili koleksiyonlar yüklenirken kartezyen patlamayı önlemek için [bölünmüş sorguları](https://learn.microsoft.com/en-us/ef/core/querying/single-split-queries) destekler. ## Yaygın LINQ Mülakat Soruları Teknik mülakatlar sıklıkla kavramsal sorular ve canlı kodlama yoluyla LINQ anlayışını sorgular. Aşağıdaki senaryolar .NET geliştirici mülakatlarında düzenli olarak karşımıza çıkar. ### "IEnumerable ve IQueryable arasındaki fark nedir?" `IEnumerable` bellekteki temsilcilerle çalışır. Her zincirlenen operatör, elemanları birer birer işleyen bir yineleyici oluşturur. Çalışma zamanı operatörler arasında optimize edemez. `IQueryable` ifade ağaçlarıyla çalışır. Tüm sorgu, bir sağlayıcının (örneğin EF Core) SQL'e çevirdiği bir veri yapısına derlenir. Bu, sunucu tarafı filtreleme, sıralama ve projeksiyon sağlar. ```csharp // IQueryableDemo.cs // Expression tree, translates to SQL WHERE clause IQueryable dbQuery = context.Orders.Where(o => o.Amount > 1000); // Delegate, executes in C# memory IEnumerable memoryQuery = orders.Where(o => o.Amount > 1000); ``` Harici veri kaynaklarını sorgularken `IQueryable` seçilmelidir. Bellek içi koleksiyonlar veya sorgunun regex veya özel yöntemler gibi yalnızca C#'a özgü özellikler kullanması gerektiğinde `IEnumerable` seçilmelidir. ### "Bir koleksiyonda yinelenenler nasıl bulunur?" Bu kodlama sorusu `GroupBy` ve filtrelemeyi test eder: ```csharp // FindDuplicates.cs var emails = new[] { "a@test.com", "b@test.com", "a@test.com", "c@test.com" }; var duplicates = emails .GroupBy(e => e, StringComparer.OrdinalIgnoreCase) .Where(g => g.Count() > 1) .Select(g => g.Key); // Output: ["a@test.com"] ``` Çözüm, elemana göre gruplar, birden fazla üyesi olan grupları filtreler ve anahtarı projekte eder. `StringComparer.OrdinalIgnoreCase` parametresi büyük/küçük harf duyarsız e-posta eşleştirmesini sağlar. ### "LINQ ile sayfalama nasıl uygulanır?" ```csharp // Pagination.cs public IEnumerable GetProductsPage(int pageNumber, int pageSize) { return context.Products .OrderBy(p => p.Id) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .ToList(); } ``` `OrderBy` cümlesi deterministik sayfalama için zorunludur. Onsuz, veritabanı motorları satırları rastgele sırada döndürebilir, bu da öğelerin birden fazla sayfada görünmesine veya tamamen kaybolmasına neden olur. Daha fazla [C# mülakat sorusu](/technologies/dotnet/interview-questions/csharp-advanced-features) için SharpSkill, desen eşleme, kayıtlar ve nullable referans türleri dahil ileri düzey özellikleri kapsar. ## Bakımı Kolay LINQ Sorguları Yazma Sorgu okunabilirliği, zincirler beş veya altı operatörü aştığında hızla bozulur. Ara sonuçlar isimli değişkenlere çıkarılmalı veya karmaşık mantık ayrı yöntemlere bölünmelidir. ```csharp // MaintainableLINQ.cs public IEnumerable GenerateReports(IEnumerable orders) { var ordersByCustomer = GroupOrdersByCustomer(orders); var reportsWithMetrics = CalculateCustomerMetrics(ordersByCustomer); return ApplyBusinessRules(reportsWithMetrics); } private IEnumerable> GroupOrdersByCustomer( IEnumerable orders) { return orders .Where(o => o.Status == OrderStatus.Completed) .GroupBy(o => o.CustomerId); } private IEnumerable CalculateCustomerMetrics( IEnumerable> groups) { return groups.Select(g => new CustomerReport { CustomerId = g.Key, TotalSpent = g.Sum(o => o.Amount), OrderCount = g.Count(), AverageOrderValue = g.Average(o => o.Amount) }); } ``` Bu yapı, her dönüşümü izolasyonda test edilebilir hale getirir. Yöntem adları, satır içi yorumlardan daha iyi niyet belgelemelidir. ## .NET Geliştiricileri İçin Temel Çıkarımlar - Ertelenmiş yürütme, numaralandırmaya kadar sorgu değerlendirmesini erteler. Anlık görüntü davranışı gerektiğinde veya çoklu numaralandırmalar bir veri kaynağına tekrar tekrar ulaşacağında sonuçları somutlaştırmak için `ToList()` veya `ToArray()` kullanılmalıdır. - `GroupBy` tüm kaynağı tamponlar. Büyük veri setleri için satırları belleğe çekmek yerine gruplamayı EF Core ile veritabanına aktarılmalıdır. - `SelectMany` iç içe koleksiyonları düzleştirir. İki parametreli aşırı yükleme, birleşik projeksiyonlar için hem üst hem de alt elemanlara erişim sağlar. - `IQueryable`, sağlayıcı çevirisi için ifade ağaçları oluşturur. `IEnumerable`, temsilcileri bellekte yürütür. Yanlış arayüzü seçmek tam tablo taramalarına yol açar. - Operatör yerleşimi [EF Core performansı](/blog/dotnet/ef-core-performance-best-practices) için önemlidir. Filtreleri sunucu tarafında çalıştırmak için `Where`, `OrderBy` ve `Take` `ToList()`'ten önce yerleştirilmelidir. - Mülakat soruları sıklıkla ertelenmiş yürütme anlayışını, `GroupBy` ile yinelenen tespitini ve `IEnumerable` vs. `IQueryable` ayrımını test eder. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/dotnet/csharp-linq-advanced-operators-performance-2026