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.

Advanced C# LINQ Operators and Performance Optimization

İ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.

DeferredExecutionDemo.cscsharp
var numbers = new List<int> { 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ı.

OrderAnalytics.cscsharp
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.

ProductCatalog.cscsharp
public record Category(string Name, List<Product> 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:

QuerySyntaxFlatten.cscsharp
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

MultipleEnumerationProblem.cscsharp
IEnumerable<Order> GetExpensiveOrders(IEnumerable<Order> orders)
{
    var filtered = orders.Where(o => o.Amount > 1000);
    
    // WARNING: Enumerates twice if orders is not materialized
    if (!filtered.Any())
        return Enumerable.Empty<Order>();
    
    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:

FixedMultipleEnumeration.cscsharp
IEnumerable<Order> GetExpensiveOrders(IEnumerable<Order> orders)
{
    var filtered = orders.Where(o => o.Amount > 1000).ToList();
    
    if (filtered.Count == 0)
        return Enumerable.Empty<Order>();
    
    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:

İşlemYavaş VersiyonHızlı VersiyonNotlar
Sayımcollection.Count()collection.CountICollection<T> için özellik kullanın
Eleman erişimicollection.ElementAt(5)collection[5]IList<T> için indeksleyici kullanın
Varlık kontrolücollection.Count() > 0collection.Any()Any() kısa devre yapar
İlk eşleşmecollection.Where(x).First()collection.First(x)Tek geçiş vs. iki yineleyici

.NET mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

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.

CustomAggregation.cscsharp
var transactions = new List<Transaction>
{
    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.

EFCoreQueryOptimization.cscsharp
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ı 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<T> 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<T> 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.

IQueryableDemo.cscsharp
// Expression tree, translates to SQL WHERE clause
IQueryable<Order> dbQuery = context.Orders.Where(o => o.Amount > 1000);

// Delegate, executes in C# memory
IEnumerable<Order> 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:

FindDuplicates.cscsharp
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?"

Pagination.cscsharp
public IEnumerable<Product> 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 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.

MaintainableLINQ.cscsharp
public IEnumerable<CustomerReport> GenerateReports(IEnumerable<Order> orders)
{
    var ordersByCustomer = GroupOrdersByCustomer(orders);
    var reportsWithMetrics = CalculateCustomerMetrics(ordersByCustomer);
    return ApplyBusinessRules(reportsWithMetrics);
}

private IEnumerable<IGrouping<string, Order>> GroupOrdersByCustomer(
    IEnumerable<Order> orders)
{
    return orders
        .Where(o => o.Status == OrderStatus.Completed)
        .GroupBy(o => o.CustomerId);
}

private IEnumerable<CustomerReport> CalculateCustomerMetrics(
    IEnumerable<IGrouping<string, Order>> 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.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

.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ı 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.
Günün meydan okuması

.NET kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

23 Ağustos 2026 tarihinde güncellendi

Etiketler

#C#
#LINQ
#.NET
#Performans
#Mülakat

Paylaş

İlgili makaleler