ู‚ุจู„ ู…ุง ู†ุจุฏุฃ ู†ุชูƒู„ู… ุนู† ุงู„ู€ LINQ ูˆู‡ูŠ ุฅูŠู‡ ุฃุตู„ู‹ุงุŒ ู‡ู†ุงุฎุฏ ู…ู‚ุฏู…ุฉ ุจุณูŠุทุฉ ุนู† ู…ุดูƒู„ุฉ ู‚ุงุจู„ุชู†ุง ูˆู‡ู†ู…ุดูŠ ุฎุทูˆุฉ ุจุฎุทูˆุฉ ู„ุญุฏ ู…ุง ู†ุญู„ู‡ุง ุจุฃุญุณู† ุทุฑูŠู‚ุฉ.

ูˆุฏู‡ ู‡ูŠูˆุถุญ ู„ู†ุง ุฅูŠู‡ ูุงูŠุฏุฉ ุงู„ู€ LINQ ูˆุงู„ู†ุงุณ ุงู„ู„ูŠ ุนู…ู„ูˆู‡ุง ูƒุงู†ูˆุง ุจูŠููƒุฑูˆุง ุฅุฒุงูŠ.

ู‚ุจู„ ู…ุง ู†ุจุฏุฃ

ู†ุจุฏุฃ ุจู…ุซุงู„ ุจุณูŠุท ู†ูู‡ู… ู…ู†ู‡ ูุงูŠุฏุชู‡ุง ูˆุฅุฒุงูŠ ุนู…ู„ู†ุงู‡ุง ูˆู„ูŠู‡ุŸ

ู‡ู†ุนู…ู„ Class ุงุณู…ู‡ Employee ูˆู†ุนู…ู„ ู…ู†ู‡ List.

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public int Salary { get; set; }
    public string Address { get; set; }
}
 
// In Main method or wherever you initialize
List<Employee> employees = new List<Employee>
{
    new Employee { Id = 1, Name = "Ahmed", Gender = "Male", Salary = 6000, Address = "Cairo" },
    new Employee { Id = 2, Name = "Salma", Gender = "Female", Salary = 4500, Address = "Alex" },
    new Employee { Id = 3, Name = "Ali", Gender = "Male", Salary = 8000, Address = "Cairo" },
    new Employee { Id = 4, Name = "Sara", Gender = "Female", Salary = 4800, Address = "Tanta" },
    // Add more employees as needed
};

Printing List of object

ู…ู…ูƒู† ู†ุณุชุฎุฏู… ุงู„ู€ Foreach ุนุดุงู† ู†ุทุจุน ุงู„ู„ูŠุณุชุฉ ุฏูŠ.

foreach (var employee in employees)
{
    Console.WriteLine(employee);
}
 
// Output will likely be something like:
// YourNameSpace.Employee
// YourNameSpace.Employee
// ...

ู‡ู†ู„ุงู‚ูŠ ุฅู†ู‡ ุจูŠุทุจุน ุงุณู… ุงู„ู€ namespace ูˆุงุณู… ุงู„ู€ class ุจุงู„ุดูƒู„ ุฏู‡. ุฏู‡ ุจุณุจุจ ุงู„ู€ ToString() method ุงู„ู„ูŠ ู…ูˆุฌูˆุฏุฉ ุชู„ู‚ุงุฆูŠ ููŠ ุงู„ู€ System.ObjectุŒ ุงู„ู„ูŠ ุฃูŠ class ููŠ C# ุจูŠูˆุฑุซ ู…ู†ู‡ ุจุดูƒู„ ุชู„ู‚ุงุฆูŠ.

ุนุดุงู† ู†ุฎู„ูŠ ุงู„ุทุจุงุนุฉ ุดูƒู„ู‡ุง ุฃุญุณู†ุŒ ู…ู…ูƒู† ู†ุนู…ู„ override ู„ู„ู€ ToString() method ุฏูŠ ุฌูˆู‡ ุงู„ู€ Employee class.

// Inside Employee Class
public override string ToString()
{
    // Customize the string representation
    return $"Id: {Id} - Name: {Name} - Gender: {Gender} - Salary: {Salary} - Address: {Address}";
}

ุฏู„ูˆู‚ุชูŠ ู„ูˆ ุทุจุนู†ุง ุชุงู†ูŠุŒ ู‡ูŠุธู‡ุฑ ุจูŠุงู†ุงุช ูƒู„ ู…ูˆุธู ุจุดูƒู„ ุฃูˆุถุญ.

ู…ู‚ุฏู…ุฉ: ู†ุนู…ู„ Query ู„ู„ุฏุงุชุง

ู†ูุชุฑุถ ุฅู†ู†ุง ุนุงูŠุฒูŠู† ู†ุฌูŠุจ ูƒู„ ุงู„ู…ูˆุธููŠู† ุงู„ู„ูŠ ุงู„ู…ุฑุชุจ ุจุชุงุนู‡ู… ุฃู‚ู„ ู…ู† 5000 ุฌู†ูŠู‡.

ุงู„ู…ูˆุธููŠู† ุงู„ู„ูŠ ู…ุฑุชุจู‡ู… ุฃู‚ู„ ู…ู† 5000

ุงู„ุทุฑูŠู‚ุฉ ุงู„ู‚ุฏูŠู…ุฉ (Old way)

ูƒู†ุง ุจู†ุนู…ู„ loop ูˆู†ุญุท if condition ูˆู†ุถูŠู ุงู„ู…ูˆุธููŠู† ุงู„ู„ูŠ ุจูŠุญู‚ู‚ูˆุง ุงู„ุดุฑุท ู„ู€ list ุฌุฏูŠุฏุฉ.

List<Employee> filteredList = new List<Employee>();
foreach (var employee in employees)
{
    if (employee.Salary < 5000)
    {
        filteredList.Add(employee);
    }
}
 
// Print the filtered list
Console.WriteLine("Employees with Salary < 5000:");
foreach (var employee in filteredList)
{
    Console.WriteLine(employee); // Uses the overridden ToString()
}

ู…ุดูƒู„ุฉ ุงู„ุทุฑูŠู‚ุฉ ุฏูŠ:

  • ู„ูˆ ุงุณุชุฎุฏู…ู†ุง ู†ูุณ ุงู„ู€ logic ุฏู‡ (ุงู„ู…ุฑุชุจ ุฃู‚ู„ ู…ู† 5000) ููŠ ุฃูƒุชุฑ ู…ู† ู…ูƒุงู† ููŠ ุงู„ูƒูˆุฏุŒ ูˆุฌูŠู†ุง ุจุนุฏ ูƒุฏู‡ ุญุจูŠู†ุง ู†ุบูŠุฑ ุงู„ุดุฑุท (ู…ุซู„ู‹ุง ู†ุฎู„ูŠู‡ ุฃู‚ู„ ู…ู† 6000)ุŒ ู‡ู†ุถุทุฑ ู†ุนุฏู‘ู„ ููŠ ูƒู„ ุงู„ุฃู…ุงูƒู† ุฏูŠ. ุฏู‡ ุจูŠุฒูˆุฏ ุงุญุชู…ุงู„ูŠุฉ ุงู„ุฎุทุฃ ูˆุจูŠุตุนุจ ุงู„ุตูŠุงู†ุฉ.

ูุงู„ุญู„ ุฅู†ู†ุง ู†ุนู…ู„ Method ุจุชุนู…ู„ ุงู„ูู„ุชุฑุฉ ุฏูŠุŒ ุนุดุงู† ู„ูˆ ุญุจูŠู†ุง ู†ุบูŠุฑ ุงู„ู€ logicุŒ ู†ุบูŠุฑู‡ ููŠ ู…ูƒุงู† ูˆุงุญุฏ ุจุณ. ูˆุงู„ุฃุญุณู† ูƒู…ุงู† ุฅู†ู†ุง ู†ุนู…ู„ู‡ุง ูƒู€ Extension Method ุนุดุงู† ุชุจู‚ู‰ ุณู‡ู„ุฉ ุงู„ุงุณุชุฎุฏุงู… ู…ุน ุฃูŠ List<Employee>.

ู†ุนู…ู„ ู…ูŠุซูˆุฏ (Make Method)

ู‡ู†ุนู…ู„ static class ูˆู†ุถูŠู ููŠู‡ extension method ู„ู„ู€ List<Employee>.

public static class ListExtensions
{
    // Specific filter method (not ideal)
    public static List<Employee> FilterEmployeesWithSalaryLessThan5000(this List<Employee> employees)
    {
        List<Employee> filteredEmployees = new List<Employee>();
        foreach (var employee in employees)
        {
            if (employee.Salary < 5000)
            {
                filteredEmployees.Add(employee);
            }
        }
        return filteredEmployees;
    }
}
 
// How to use it:
// var filteredByMethod = employees.FilterEmployeesWithSalaryLessThan5000();

ูƒุฏู‡ ุญู„ูŠู†ุง ู…ุดูƒู„ุฉ ุชูƒุฑุงุฑ ุงู„ูƒูˆุฏ ูˆุชุนุฏูŠู„ู‡ ููŠ ูƒุฐุง ู…ูƒุงู†.

ุทูŠุจุŒ ู„ูˆ ุนุงูŠุฒ ุฃุนู…ู„ ูู„ุชุฑุฉ ุชุงู†ูŠุฉุŸ ู…ุซู„ู‹ุงุŒ ุฃุฌูŠุจ ุงู„ู…ูˆุธููŠู† ุงู„ุฐูƒูˆุฑ ุจุณ (Gender == "Male") ุฃูˆ ุงู„ู„ูŠ ุณุงูƒู†ูŠู† ููŠ ุทู†ุทุง (Address == "Tanta")ุŸ ู‡ู„ ู‡ุนู…ู„ method ุฌุฏูŠุฏุฉ ู„ูƒู„ ุดุฑุทุŸ ุฃูƒูŠุฏ ู„ุฃ.

ุงุณุชุฎุฏุงู… ุงู„ู€ Delegate

ู„ูˆ ุจุตูŠู†ุง ุนู„ู‰ ุงู„ู€ methods ุงู„ู„ูŠ ู…ู…ูƒู† ู†ุนู…ู„ู‡ุง ู„ู„ูู„ุชุฑุฉ ุงู„ู…ุฎุชู„ูุฉ:

// Filter by Tanta Address (Old way - specific method)
public static List<Employee> FilterEmployeesFromTanta(this List<Employee> employees)
{
    List<Employee> filteredEmployees = new List<Employee>();
    foreach (var employee in employees)
    {
        if (employee.Address == "Tanta") // The only difference is this condition
        {
            filteredEmployees.Add(employee);
        }
    }
    return filteredEmployees;
}
 
// Filter Male Employees (Old way - specific method)
public static List<Employee> FilterMaleEmployees(this List<Employee> employees)
{
    List<Employee> filteredEmployees = new List<Employee>();
    foreach (var employee in employees)
    {
        if (employee.Gender == "Male") // The only difference is this condition
        {
            filteredEmployees.Add(employee);
        }
    }
    return filteredEmployees;
}

ู‡ู†ู„ุงุญุธ ุฅู† ุงู„ูุฑู‚ ุงู„ูˆุญูŠุฏ ุจูŠู† ุงู„ู€ methods ุฏูŠ ู‡ูˆ ุงู„ุดุฑุท (if condition).

ุงู„ุญู„ ู‡ู†ุง ุฅู†ู†ุง ู†ุฎู„ูŠ ุงู„ู€ method ุจุชุงุนุฉ ุงู„ูู„ุชุฑุฉ ุชุงุฎุฏ ุงู„ุดุฑุท ุฏู‡ ูƒู€ parameter. ูˆุนุดุงู† ุงู„ุดุฑุท ุฏู‡ ุนุจุงุฑุฉ ุนู† function ุตุบูŠุฑุฉ ุจุชุฑุฌุน true ุฃูˆ falseุŒ ู‡ู†ุณุชุฎุฏู… delegate ู…ู†ุงุณุจ. ุงู„ู€ delegate ุงู„ุฃู†ุณุจ ู‡ู†ุง ู‡ูˆ Predicate ู„ุฅู†ู‡ุง ุจุชุงุฎุฏ parameter ู…ู† ู†ูˆุน T (ุงู„ู„ูŠ ู‡ูˆ Employee ููŠ ุญุงู„ุชู†ุง) ูˆุจุชุฑุฌุน bool.

// In the ListExtensions class
public static class ListExtensions
{
    // Generic filter method using Predicate delegate
    public static List<Employee> FilterEmployees(this List<Employee> employees, Predicate<Employee> predicate)
    {
        List<Employee> filteredEmployees = new List<Employee>();
        foreach (var employee in employees)
        {
            // Call the predicate to check the condition
            if (predicate(employee))
            {
                filteredEmployees.Add(employee);
            }
        }
        return filteredEmployees;
    }
}
 
// In the Main method or wherever you call it:
 
// Define boolean methods matching the Predicate signature
public static bool IsMaleEmployee(Employee employee)
{
    return employee.Gender == "Male";
}
 
public static bool IsSalaryLessThan5000(Employee employee) // Changed from 8000 in original text
{
    return employee.Salary < 5000;
}
 
public static bool IsFromTanta(Employee employee)
{
    return employee.Address == "Tanta";
}
 
// Call the generic filter method, passing the condition method as a parameter
var maleEmployees = employees.FilterEmployees(IsMaleEmployee);
var lowSalaryEmployees = employees.FilterEmployees(IsSalaryLessThan5000);
var tantaEmployees = employees.FilterEmployees(IsFromTanta);
 
// Print results (example for males)
Console.WriteLine("\nMale Employees:");
foreach (var employee in maleEmployees)
{
    Console.WriteLine(employee);
}

ูˆุจูƒุฏู‡ ุงู„ู…ุดูƒู„ุฉ ุจู‚ุช ู…ุญู„ูˆู„ุฉ ุจุดูƒู„ ูƒูˆูŠุณ ุฌุฏู‹ุง. ุนู†ุฏู†ุง method ูˆุงุญุฏุฉ ู„ู„ูู„ุชุฑุฉุŒ ูˆุจู†ู…ุฑุฑ ู„ู‡ุง ุงู„ุดุฑุท ุงู„ู„ูŠ ุนุงูŠุฒูŠู†ู‡.

ุทูŠุจุŒ ู„ูˆ ุงุญุชุฌู†ุง ู†ุนู…ู„ class ุฌุฏูŠุฏุŒ ู…ุซู„ู‹ุง ProductุŒ ูˆู†ุนู…ู„ ู„ู‡ ูู„ุชุฑุฉ ุจู†ูุณ ุงู„ุทุฑูŠู‚ุฉุŸ ู‡ู„ ู‡ู†ูƒุฑุฑ ู†ูุณ ุงู„ู€ FilterEmployees method ูˆู†ุนู…ู„ FilterProductsุŸ ุฃูƒูŠุฏ ู„ุฃ.

ู‡ู†ุง ูŠูŠุฌูŠ ุฏูˆุฑ ุงู„ู€ Generics.

ุงุณุชุฎุฏุงู… ุงู„ู€ Cs Generics

ุนุดุงู† ู†ุฎู„ูŠ ุงู„ู€ Filter method ุจุชุงุนุชู†ุง ุชุดุชุบู„ ู…ุน ุฃูŠ type (ุณูˆุงุก Employee ุฃูˆ Product ุฃูˆ ุบูŠุฑู‡)ุŒ ู‡ู†ุณุชุฎุฏู… ุงู„ู€ Generics. ู‡ู†ุฎู„ูŠ ุงู„ู€ method ุชุงุฎุฏ type parameter (T) ูˆุชุดุชุบู„ ุนู„ูŠู‡.

// Updated ListExtensions class with Generics
public static class GenericListExtensions // Renamed for clarity
{
    // Generic Filter method using Generics and Predicate
    public static List<T> Filter<T>(this List<T> items, Predicate<T> predicate)
    {
        List<T> filteredItems = new List<T>();
        foreach (var item in items)
        {
            if (predicate(item))
            {
                filteredItems.Add(item);
            }
        }
        return filteredItems;
    }
}
 
// Example Product class
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public double Price { get; set; }
    public override string ToString() => $"Id: {Id}, Name: {Name}, Category: {Category}, Price: {Price}";
}
 
// In Main method:
List<Product> products = new List<Product>
{
    new Product { Id = 101, Name = "Laptop", Category = "Devices", Price = 25000 },
    new Product { Id = 102, Name = "Keyboard", Category = "Devices", Price = 1500 },
    new Product { Id = 103, Name = "T-Shirt", Category = "Clothing", Price = 500 },
    new Product { Id = 104, Name = "Mouse", Category = "Devices", Price = 800 },
};
 
// Define predicate methods for Product
public static bool IsDeviceAndLessThan20000(Product product)
{
    return product.Category == "Devices" && product.Price < 20000;
}
 
// Call the generic Filter method
var filteredEmployeesGeneric = employees.Filter<Employee>(IsMaleEmployee); // Specify Employee type
var filteredProductsGeneric = products.Filter<Product>(IsDeviceAndLessThan20000); // Specify Product type
 
// Print results (example for products)
Console.WriteLine("\nFiltered Products (Devices < 20000):");
foreach (var product in filteredProductsGeneric)
{
    Console.WriteLine(product);
}

ุฏู„ูˆู‚ุชูŠ ุงู„ู€ Filter<T> method ุจู‚ุช ุดุบุงู„ุฉ ู…ุน ุฃูŠ List ูˆุฃูŠ ุดุฑุท.

ุนุดุงู† ู†ุฎู„ูŠ ุงู„ู€ Syntax ุฃุณู‡ู„ ูˆุฃูƒุชุฑ ุงุฎุชุตุงุฑู‹ุงุŒ ุจุฏู„ ู…ุง ู†ุนู…ู„ method ู…ู†ูุตู„ุฉ ู„ูƒู„ ุดุฑุท (ุฒูŠ IsMaleEmployee ูˆ IsDeviceAndLessThan20000)ุŒ ู…ู…ูƒู† ู†ุณุชุฎุฏู… Lambda Expressions in Csharp. ุบุงู„ุจู‹ุง ู…ุด ู‡ู†ุญุชุงุฌ ู†ุณุชุฎุฏู… ุงู„ู€ methods ุฏูŠ ุชุงู†ูŠุŒ ูุงู„ู€ Lambda ุจุชูƒูˆู† ุฃู†ุณุจ.

// Using Lambda Expressions directly with the Filter method
var filteredEmployeesLambda = employees.Filter(employee => employee.Gender == "Male");
var filteredProductsLambda = products.Filter(product => product.Category == "Devices" && product.Price < 20000);
 
// Note: We don't need to specify <Employee> or <Product> because the compiler infers it.
 
// Print results (example for products lambda)
Console.WriteLine("\nFiltered Products (Lambda):");
foreach (var product in filteredProductsLambda)
{
    Console.WriteLine(product);
}

Where (LINQ)

ูƒู„ ุงู„ู„ูŠ ุนู…ู„ู†ุงู‡ ููˆู‚ ุฏู‡ ุนุดุงู† ู†ูˆุตู„ ู„ู€ method ูู„ุชุฑุฉ ุนุงู…ุฉ ูˆู…ุฑู†ุฉุŒ ู‡ูˆ ุจุงู„ุธุจุท ุงู„ู„ูŠ LINQ ุจูŠู‚ุฏู…ู‡ูˆู„ู†ุง ุฌุงู‡ุฒ ููŠ operator ุงุณู…ู‡ Where.

ุงู„ู€ Where ู‡ูˆ Filtration Operator ููŠ LINQ.

// The Filter<T> method we created:
// var filteredProductsManual = products.Filter(product => product.Category == "Devices" && product.Price < 20000);
 
// Using LINQ's built-in Where (Fluent Syntax):
var filteredProductsLinqFluent = products.Where(product => product.Category == "Devices" && product.Price < 20000);
 
// Using LINQ's built-in Where (Query Syntax):
var filteredProductsLinqQuery = from p in products // p is a range variable representing each product
                                where p.Category == "Devices" && p.Price < 20000
                                select p; // Select the product itself
 
// Print results (example for LINQ Fluent)
Console.WriteLine("\nFiltered Products (LINQ Fluent Where):");
foreach (var product in filteredProductsLinqFluent)
{
    Console.WriteLine(product);
}

ุฒูŠ ู…ุง ุฅู†ุช ุดุงูŠูุŒ LINQ ุจูŠูˆูุฑ ู„ู†ุง Where ุงู„ู„ูŠ ุจุชุนู…ู„ ู†ูุณ ูˆุธูŠูุฉ ุงู„ู€ Filter<T> ุจุชุงุนุชู†ุงุŒ ุจุณ ุจุดูƒู„ ู…ุฏู…ุฌ ููŠ ุงู„ู„ุบุฉ.

Indexed Where

ุงู„ู€ Where method ู„ูŠู‡ุง overload.

  • ุงู„ุฃูˆู„ (ุงู„ู„ูŠ ุงุณุชุฎุฏู…ู†ุงู‡): ุจูŠุงุฎุฏ parameter ูˆุงุญุฏ ุจุณ (ุงู„ู„ูŠ ู‡ูˆ ุงู„ู€ predicate ุงู„ู„ูŠ ุจูŠุดุชุบู„ ุนู„ู‰ ุงู„ุนู†ุตุฑ ู†ูุณู‡ุŒ ุฒูŠ product => ...).
  • ุงู„ุชุงู†ูŠ (Indexed Where): ุจูŠุงุฎุฏ ุงุชู†ูŠู† parameters:
    1. ุงู„ุนู†ุตุฑ ู†ูุณู‡ (product).
    2. ุงู„ู€ index ุจุชุงุน ุงู„ุนู†ุตุฑ ุฏู‡ ููŠ ุงู„ู€ sequence (ุจูŠุจุฏุฃ ู…ู† 0).

ูู…ุซู„ู‹ุงุŒ ู„ูˆ ุนุงูŠุฒ ุฃุฌูŠุจ ุฃูˆู„ 10 ู…ู†ุชุฌุงุช ุจุดุฑุท ูŠูƒูˆู†ูˆุง ู…ู† ู†ูˆุน Devices:

// Using Indexed Where (Fluent Syntax only)
var first10Devices = products.Where((p, index) => index < 10 && p.Category == "Devices");
 
Console.WriteLine("\nFirst 10 Devices (Indexed Where):");
foreach (var product in first10Devices)
{
    Console.WriteLine(product);
}

ู…ู„ุญูˆุธุฉ ู…ู‡ู…ุฉ: ุงู„ู€ Indexed Where ุฏู‡ ู…ุชุงุญ ุจุณ ููŠ ุงู„ู€ Fluent Syntax (ุทุฑูŠู‚ุฉ ุงู„ู€ methods)ุŒ ูˆู…ุด ู…ุชุงุญ ููŠ ุงู„ู€ Query Syntax (ุทุฑูŠู‚ุฉ from...where...select). ู‡ู†ูˆุถุญ ุงู„ูุฑู‚ ุจูŠู†ู‡ู… ุชุญุช.

LINQ

ู…ู‚ุฏู…ุฉ

  • LINQ stands for Language Integrated Query. (ุงุณุชุนู„ุงู… ู…ุฏู…ุฌ ููŠ ุงู„ู„ุบุฉ).
  • ุจู†ู‚ุฏุฑ ู†ุนู…ู„ ุจูŠู‡ุง Queries (ุงุณุชุนู„ุงู…ุงุช) ุนู„ู‰ ุงู„ุฏุงุชุง ุจุชุงุนุชู†ุง ุจุณู‡ูˆู„ุฉ ุฌูˆู‡ ุงู„ูƒูˆุฏ ุจุชุงุน C#.
  • ู‡ูŠ ุนุจุงุฑุฉ ุนู† ู…ุฌู…ูˆุนุฉ ูƒุจูŠุฑุฉ ู…ู† ุงู„ู€ functions (ุฃูƒุชุฑ ู…ู† 40ุŒ ูˆูƒู„ ูˆุงุญุฏุฉ ู„ูŠู‡ุง ุฃูƒุชุฑ ู…ู† overload).
  • ุงู„ู€ functions ุฏูŠ ููŠ ุงู„ุญู‚ูŠู‚ุฉ ุนุจุงุฑุฉ ุนู† Extension Methods ู…ุนู…ูˆู„ุฉ ู„ู„ู€ interface ุงู„ู„ูŠ ุงุณู…ู‡ IEnumerable ูˆุฃูŠ class ุจูŠุนู…ู„ ู„ู‡ implement ุฃูˆ ุจูŠูˆุฑุซ ู…ู†ู‡ (ุฒูŠ List, Array, IReadOnlyList ูˆุบูŠุฑู‡ู… ูƒุชูŠุฑ).
  • ุงู„ู€ functions ุฏูŠ ุจู†ุณู…ูŠู‡ุง ุจุฑุถูˆ LINQ Operators ูˆูƒู„ู‡ู… ู…ูˆุฌูˆุฏูŠู† ุฌูˆู‡ static class ุงุณู…ู‡ Enumerable.
  • ุงู„ู€ Operators ุฏูŠ ู…ุชู‚ุณู…ุฉ ู„ู€ 13 Category (ู…ุฌู…ูˆุนุฉ) ุญุณุจ ูˆุธูŠูุชู‡ุง (ุฒูŠ Filtration, Projection, Ordering, Grouping, etc.).
  • ุทุจุนู‹ุงุŒ ุงู„ู€ Return type ุจุชุงุน ู…ุนุธู… ุงู„ู€ LINQ operators ุจูŠูƒูˆู† IEnumerable (ุฃูˆ IQueryable ุฒูŠ ู…ุง ู‡ู†ุดูˆู)ุŒ ูˆู…ู…ูƒู† ู†ุญูˆู„ ุงู„ู†ุชูŠุฌุฉ ุฏูŠ ู„ู€ List ุฃูˆ Array ุจุณู‡ูˆู„ุฉ ู„ูˆ ู…ุญุชุงุฌูŠู† (ุจุงุณุชุฎุฏุงู… ToList() ุฃูˆ ToArray()).

ุทุจ ุฅูŠู‡ ุนู„ุงู‚ุชู‡ุง ุจุงู„ู€ Databases ูˆูุงูŠุฏุชู‡ุงุŸ

  • ุงู„ู€ LINQ functions ุฃูˆ Operators ุฏูŠ ุชุนุชุจุฑ ุชุทุจูŠู‚ ู„ู„ู€ concepts ุจุชุงุนุฉ ู„ุบุฉ ุงุณุชุนู„ุงู… ุงู„ุจูŠุงู†ุงุช ุงู„ู‚ูŠุงุณูŠุฉ SQLุŒ ูˆุจุงู„ุชุญุฏูŠุฏ ุงู„ุฌุฒุก ุงู„ุฎุงุต ุจุงู„ู€ Data Query Language (DQL) ุงู„ู„ูŠ ู‡ูˆ ุฃู…ุฑ SELECT ุจูƒู„ ุงู„ุฅู…ูƒุงู†ูŠุงุช ุงู„ู„ูŠ ู…ุนุงู‡ (ุฒูŠ WHERE, ORDER BY, GROUP BY, JOIN). ูŠุนู†ูŠ ูƒุฃู†ู†ุง ุฎุฏู†ุง ุงู„ู€ SELECT statement ูˆุญุทูŠู†ุงู‡ุง ุฌูˆู‡ C#.
  • ุงู„ูุงุฆุฏุฉ ุงู„ูƒุจูŠุฑุฉ: ุจุฏู„ ู…ุง ู†ูƒุชุจ SQL query ุตุฑูŠุญ ููŠ ุงู„ูƒูˆุฏ ุจุชุงุนู†ุง (ูˆุฏู‡ ู‡ูŠุฎู„ูŠู†ุง ู…ุฑุชุจุทูŠู† ุจู€ database server ู…ุนูŠู† ุฒูŠ SQL Server ุฃูˆ MySQL)ุŒ ุจู†ูƒุชุจ LINQ query.
  • ุงู„ู€ LINQ query ุฏู‡ ุจูŠูƒูˆู† ู…ุณุชู‚ู„ ุนู† ู†ูˆุน ุงู„ู€ database.
  • ู„ู…ุง ุจู†ุณุชุฎุฏู… LINQ ู…ุน framework ุฒูŠ Entity Framework Core (Route Course MOC)ุŒ ุงู„ู€ EF Core ู‡ูˆ ุงู„ู„ูŠ ุจูŠุชูˆู„ู‰ ู…ู‡ู…ุฉ ุชุฑุฌู…ุฉ ุงู„ู€ LINQ query ุจุชุงุนู†ุง ู„ู€ SQL query ู…ู†ุงุณุจ ู„ู„ู€ Database Management System (DBMS) ุงู„ู„ูŠ ุฅุญู†ุง ุดุบุงู„ูŠู† ุนู„ูŠู‡ (ุณูˆุงุก ูƒุงู† SQL Server, PostgreSQL, SQLite, etc.).
  • ุฏู‡ ุจูŠุฎู„ูŠ ุงู„ูƒูˆุฏ ุจุชุงุนู†ุง portable ุฃูƒุชุฑุŒ ู„ูˆ ุญุจูŠู†ุง ู†ุบูŠุฑ ู†ูˆุน ุงู„ู€ database ููŠ ุงู„ู…ุณุชู‚ุจู„ุŒ ู…ุด ู‡ู†ุญุชุงุฌ ู†ุบูŠุฑ ุงู„ู€ LINQ queries ุจุชุงุนุชู†ุง.

Sequence (ุงู„ู…ุชุณู„ุณู„ุฉ)

ุฅุญู†ุง ุจู†ุณุชุฎุฏู… ุงู„ู€ LINQ Operators ู…ุน ุงู„ุฏุงุชุง ุงู„ู„ูŠ ุจุชูƒูˆู† ู…ุชุฎุฒู†ุฉ ููŠ ุดูƒู„ Sequence (ู…ุชุณู„ุณู„ุฉ)ุŒ ุจุบุถ ุงู„ู†ุธุฑ ู‡ูŠ ู…ุชุฎุฒู†ุฉ ููŠู†.

ู„ู…ุง ู†ู‚ูˆู„ โ€œSequenceโ€ุŒ ุจู†ู‚ุตุฏ ุฃูŠ Object ุจูŠุทุจู‚ ุงู„ู€ interface ุงู„ู„ูŠ ุงุณู…ู‡ Cs IEnumerable (ูˆุฏู‡ ู…ุนู†ุงู‡ ุฅู†ู†ุง ู†ู‚ุฏุฑ ู†ุนู…ู„ ุนู„ูŠู‡ loop ุจุงุณุชุฎุฏุงู… foreach). ุฃู…ุซู„ุฉ ุฒูŠ: List<T>, T[] (Array), Dictionary<TKey, TValue>, string, ูˆุบูŠุฑู‡ุง ู…ู† ุงู„ู€ Collections.

ุงู„ุชู‚ุณูŠู… ู„ู€ โ€œLocalโ€ ูˆ โ€œRemoteโ€ ุจูŠุนุชู…ุฏ ุนู„ู‰ ู…ุตุฏุฑ ุงู„ุฏุงุชุง:

  1. Local Sequence:

    • ู‡ูŠ ุฃูŠ Sequence ู…ูˆุฌูˆุฏุฉ ููŠ ุงู„ุฐุงูƒุฑุฉ (in-memory) ุจุชุงุนุฉ ุงู„ุฃุจู„ูƒูŠุดู† ุจุชุงุนูƒุŒ ุฒูŠ List ุฃูˆ Array ุนู…ู„ุชู‡ู… ุจู†ูุณูƒ.
    • ู„ู…ุง ุจุชุณุชุฎุฏู… LINQ ู…ุนุงู‡ุงุŒ ุงู„ุนู…ู„ูŠุฉ ุฏูŠ ุจู†ุณู…ูŠู‡ุง LINQ to Objects (L2O).
    • ููŠู‡ ูƒู…ุงู† LINQ to XML (L2XML) ู„ูˆ ุจุชุนู…ู„ query ุนู„ู‰ ูุงูŠู„ XML files ู…ูˆุฌูˆุฏ ุนู†ุฏูƒ.
    • ูƒู„ ุงู„ุนู…ู„ูŠุงุช (ุงู„ูู„ุชุฑุฉุŒ ุงู„ุชุฑุชูŠุจุŒ ุฅู„ุฎ) ุจุชุญุตู„ ุฌูˆู‡ ุงู„ู€ RAM ุจุชุงุนุฉ ุงู„ุฌู‡ุงุฒ ุงู„ู„ูŠ ุดุบุงู„ ุนู„ูŠู‡ ุงู„ุฃุจู„ูƒูŠุดู†. ู…ููŠุด ุงุชุตุงู„ ุจู…ุตุฏุฑ ุฎุงุฑุฌูŠ.
    • ุญุชู‰ ูุงูŠู„ุงุช ุงู„ู€ XML ุจู†ุนุชุจุฑู‡ุง Local ููŠ ุงู„ุณูŠุงู‚ ุฏู‡.
  2. Remote Sequence:

    • ู‡ูŠ Sequence ุงู„ุฏุงุชุง ุจุชุงุนุชู‡ุง ู…ุด ู…ูˆุฌูˆุฏุฉ ู…ุจุงุดุฑุฉ ููŠ ุงู„ุฐุงูƒุฑุฉุŒ ู„ูƒู†ู‡ุง ุฌุงูŠุฉ ู…ู† ู…ุตุฏุฑ ุจูŠุงู†ุงุช ุฎุงุฑุฌูŠ (external data source).
    • ุฃุดู‡ุฑ ู…ุซุงู„ ู‡ูˆ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช (Database). ุฃู…ุซู„ุฉ ุชุงู†ูŠุฉ ู…ู…ูƒู† ุชูƒูˆู† Web API ุฃูˆ ุฃูŠ ุฎุฏู…ุฉ ุจุชูˆูุฑ ุฏุงุชุง.
    • ู„ู…ุง ุจู†ุดุชุบู„ ู…ุน remote sequences (ุฎุตูˆุตู‹ุง ู…ุน databases ุจุงุณุชุฎุฏุงู… EF Core)ุŒ ุบุงู„ุจู‹ุง ุจู†ุชุนุงู…ู„ ู…ุน interface ุชุงู†ูŠ ุงุณู…ู‡ Cs IQueryable ุจุฏู„ IEnumerable<T>.
    • ุงู„ู€ IQueryable<T> ุจูŠุณู…ุญ ุจุชุฑุฌู…ุฉ ุงู„ู€ LINQ query ู„ู€ query language ูŠูู‡ู…ู‡ุง ุงู„ู…ุตุฏุฑ ุงู„ุฎุงุฑุฌูŠ (ุฒูŠ SQL ููŠ ุญุงู„ุฉ ุงู„ู€ database).
    • ุงู„ุนู…ู„ูŠุงุช ุฏูŠ ุจู†ุณู…ูŠู‡ุง LINQ to SQL (ู„ู„ู€ SQL Server ุจุดูƒู„ ู…ุจุงุดุฑ ุฒู…ุงู†)ุŒ LINQ to Entities (ู…ุน Entity Framework ูˆ EF Core)ุŒ ุฃูˆ LINQ to OData (ู„ูˆ ุจุชูƒู„ู… OData API).
    • ุงู„ู€ Query ู†ูุณู‡ ุจูŠุชู†ูุฐ ุนู„ู‰ ุงู„ู€ server ุฃูˆ ุงู„ู…ุตุฏุฑ ุงู„ุฎุงุฑุฌูŠุŒ ูˆุจุนุฏูŠู† ุงู„ู†ุชูŠุฌุฉ ุจุณ ู‡ูŠ ุงู„ู„ูŠ ุจุชุฑุฌุน ู„ู„ุฃุจู„ูƒูŠุดู† ุจุชุงุนูƒ.

ุจุงุฎุชุตุงุฑ:

  • ุงู„ู€ Local Sequence: ู…ูˆุฌูˆุฏุฉ ุฌูˆู‡ ุงู„ุฃุจู„ูƒูŠุดู† ูˆุชู‚ุฏุฑ ุชู„ู ุนู„ูŠู‡ุง ุจู€ foreach ููŠ ุงู„ู€ memory ุนู„ุทูˆู„.
  • ุงู„ู€ Remote Sequence: ุจุชู…ุซู„ ุฏุงุชุง ู…ูˆุฌูˆุฏุฉ ุจุฑู‡ ุงู„ุฃุจู„ูƒูŠุดู† (ุฒูŠ database table)ุŒ ุงู„ู€ query ุจูŠุชู†ูุฐ ู‡ู†ุงูƒ ูˆุงู„ู†ุชูŠุฌุฉ ุจุชุฑุฌุนู„ูƒ.

Query Syntax vs Fluent Syntax

ููŠู‡ ุทุฑูŠู‚ุชูŠู† ุฃุณุงุณูŠุชูŠู† ู„ูƒุชุงุจุฉ LINQ queries ููŠ C#:

ุงู„ู†ูˆุน ุงู„ู„ูŠ ู‡ูˆ ุงู„ู€ Method ุฏุง ุงุณู…ู‡ Fluent ุจุฑุถูˆ.

1. Fluent Syntax (Method Syntax)

ุฏูŠ ุงู„ุทุฑูŠู‚ุฉ ุงู„ู„ูŠ ุจู†ุณุชุฎุฏู… ููŠู‡ุง ุงู„ู€ LINQ operators ูƒุฃู†ู‡ุง methods ุจู†ู†ุงุฏูŠู‡ุง ุนู„ู‰ ุงู„ู€ sequence ุจุชุงุนุชู†ุง. ู„ูŠู‡ุง ุดูƒู„ูŠู†:

  • ุงู„ู€ Extension Method (ุงู„ุทุฑูŠู‚ุฉ ุงู„ุดุงุฆุนุฉ ูˆุงู„ู…ูุถู„ุฉ): ุจู†ู†ุงุฏูŠ ุงู„ู€ operator ูƒู€ extension method ู…ุจุงุดุฑุฉ ุนู„ู‰ ุงู„ู€ List ุฃูˆ ุงู„ู€ IEnumerable ุจุชุงุนู†ุง.
  • ุงู„ู€ Static Method: ุจู†ู†ุงุฏูŠ ุงู„ู€ operator ูƒู€ static method ู…ู† ุงู„ู€ Enumerable class ูˆุจู†ู…ุฑุฑ ู„ู‡ ุงู„ู€ sequence ูƒุฃูˆู„ parameter.
List<int> Numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> OddNumbers; // Result will be IEnumerable
 
// ุงู„ุทุฑูŠู‚ุฉ ุงู„ุฃูˆู„ู‰ (Static Method - ู…ุด ุจู†ุณุชุฎุฏู…ู‡ุง ูƒุชูŠุฑ ุฃูˆูŠ)
// Enumerable.Where(Source_Sequence, Predicate_Lambda)
OddNumbers = Enumerable.Where(Numbers, N => N % 2 == 1);
Console.WriteLine("Odd Numbers (Static Method): " + string.Join(", ", OddNumbers));
 
// ุงู„ุทุฑูŠู‚ุฉ ุงู„ุชุงู†ูŠุฉ (Extension Method - ุฏูŠ ุงู„ู„ูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ุฏุงูŠู…ู‹ุง)
OddNumbers = Numbers.Where(N => N % 2 == 1);
Console.WriteLine("Odd Numbers (Extension Method): " + string.Join(", ", OddNumbers));

ุงู„ู€ Fluent Syntax (ุฎุตูˆุตู‹ุง ุทุฑูŠู‚ุฉ ุงู„ู€ Extension Method) ู‡ูŠ ุงู„ุฃูƒุซุฑ ุงุณุชุฎุฏุงู…ู‹ุง ูˆู…ุฑูˆู†ุฉุŒ ุฎุตูˆุตู‹ุง ู…ุน ุงู„ุนู…ู„ูŠุงุช ุงู„ู…ุนู‚ุฏุฉ ุฃูˆ ุงู„ู…ุชุณู„ุณู„ุฉ (chaining).

2. Query Syntax (Query Expression Syntax)

  • ุฏูŠ ุทุฑูŠู‚ุฉ ูƒุชุงุจุฉ LINQ ุจุดูƒู„ ุดุจู‡ ู„ุบุฉ SQL.
  • ุจุชุจุฏุฃ ุฏุงูŠู…ู‹ุง ุจูƒู„ู…ุฉ from ุงู„ู„ูŠ ุจุชุนุฑู range variable ุจูŠู…ุซู„ ูƒู„ ุนู†ุตุฑ ููŠ ุงู„ู€ sequence (ุฒูŠ N ููŠ ุงู„ู…ุซุงู„ ุชุญุช).
  • ุจุนุฏู‡ุง ุจุชูŠุฌูŠ ุฌู…ู„ ุฒูŠ where, orderby, select, group, join.
  • ู„ุงุฒู… ุชู†ุชู‡ูŠ ุจู€ select ุฃูˆ group by.
  • ุงู„ุชุฑุชูŠุจ ุจุชุงุน ุงู„ุฌู…ู„ ููŠ ุงู„ู€ Query Syntax ุจูŠูƒูˆู† ู…ุฎุชู„ู ุดูˆูŠุฉ ุนู† SQL (ู…ุซู„ู‹ุง select ุจุชูŠุฌูŠ ููŠ ุงู„ุขุฎุฑ).
// Query Syntax example for odd numbers
OddNumbers = from N in Numbers // Define range variable N for each item in Numbers
             where N % 2 == 1  // Filter condition
             select N;        // Select the item itself
 
Console.WriteLine("Odd Numbers (Query Syntax): " + string.Join(", ", OddNumbers));

ุงู„ู€ Query Syntax ู…ู…ูƒู† ุชูƒูˆู† ุฃุณู‡ู„ ููŠ ุงู„ู‚ุฑุงุกุฉ ู„ุจุนุถ ุงู„ู†ุงุณ ุงู„ู„ูŠ ู…ุชุนูˆุฏูŠู† ุนู„ู‰ SQLุŒ ุฎุตูˆุตู‹ุง ู…ุน ุนู…ู„ูŠุงุช ุงู„ู€ Join ูˆุงู„ู€ Grouping.

3. Hybrid Syntax (ุงู„ุฎู„ูŠุท)

  • ุฃุญูŠุงู†ู‹ุง ุจู†ุญุชุงุฌ ู†ุณุชุฎุฏู… operator ู…ุด ู…ูˆุฌูˆุฏ ุฃูˆ ุตุนุจ ุงุณุชุฎุฏุงู…ู‡ ููŠ ุงู„ู€ Query Syntax (ุฒูŠ Count(), FirstOrDefault(), Take(), Skip(), ูˆุบูŠุฑู‡ุง ูƒุชูŠุฑ).
  • ููŠ ุงู„ุญุงู„ุฉ ุฏูŠุŒ ู…ู…ูƒู† ู†ูƒุชุจ ุฌุฒุก ู…ู† ุงู„ู€ query ุจุงู„ู€ Query SyntaxุŒ ูˆู†ุญุท ุงู„ู†ุชูŠุฌุฉ ุจูŠู† ู‚ูˆุณูŠู† ()ุŒ ูˆุจุนุฏูŠู† ู†ูƒู…ู„ ุนู„ูŠู‡ ุจุงู„ู€ Fluent Syntax.
// Example: Get the first product that is out of stock using Hybrid Syntax
// Assuming ProductList is a List<Product>
// var Result = (from P in ProductList // Query Syntax part
//               where P.UnitsInStock == 0
//               select P)
//              .FirstOrDefault(); // Fluent Syntax part added after the query
 
// Example with the sample data (find first product with price < 1000)
var firstCheapProduct = (from p in products
                         where p.Price < 1000
                         select p)
                        .FirstOrDefault(); // Returns the Mouse product or null if none found
 
if (firstCheapProduct != null)
{
    Console.WriteLine($"\nFirst Cheap Product (Hybrid): {firstCheapProduct}");
}
else
{
    Console.WriteLine("\nNo cheap product found (Hybrid).");
}

ุฃู†ู‡ูŠ ุทุฑูŠู‚ุฉ ุฃุณุชุฎุฏู…ู‡ุงุŸ

  • ุงู„ุฃู…ุฑ ุจูŠุฑุฌุน ู„ู„ุชูุถูŠู„ ุงู„ุดุฎุตูŠ ูˆุงู„ู…ูˆู‚ู.
  • ุงู„ู€ Fluent Syntax: ุฃูƒุซุฑ ู‚ูˆุฉ ูˆุดู…ูˆู„ูŠุฉ (ูƒู„ ุงู„ู€ operators ู…ุชุงุญุฉ)ุŒ ูˆู…ู…ุชุงุฒ ู„ู€ chaining methods.
  • ุงู„ู€ Query Syntax: ุฃุณู‡ู„ ููŠ ุงู„ู‚ุฑุงุกุฉ ู„ุนู…ู„ูŠุงุช ุงู„ู€ Join ูˆุงู„ู€ Grouping ุงู„ู…ุนู‚ุฏุฉ ุดูˆูŠุฉ.
  • ุงู„ู€ Hybrid Syntax: ุจู†ุณุชุฎุฏู…ู‡ ู„ู…ุง ู†ุญุชุงุฌ ู†ุฏู…ุฌ ุจูŠู† ุงู„ุทุฑูŠู‚ุชูŠู†.
  • ูƒุชูŠุฑ ู…ู† ุงู„ู…ุจุฑู…ุฌูŠู† ุจูŠุณุชุฎุฏู…ูˆุง Fluent Syntax ููŠ ู…ุนุธู… ุงู„ูˆู‚ุชุŒ ูˆุจูŠู„ุฌุฃูˆุง ู„ู€ Query Syntax ููŠ ุญุงู„ุงุช ุงู„ู€ Join/Group ุงู„ุตุนุจุฉ.

ุชุฌู‡ูŠุฒ ุงู„ุฏุงุชุง (Data Setup)

ุนุดุงู† ู†ุจุฏุฃ ู†ุดุชุบู„ ูุนู„ูŠู‹ุง ูˆู†ุฌุฑุจ ุงู„ู€ LINQ operators ุงู„ู…ุฎุชู„ูุฉุŒ ู‡ู†ุญุชุงุฌ ู†ุนู…ู„ dummy project ุฃูˆ ู†ุณุชุฎุฏู… classes ูˆ lists ููŠู‡ุง ุฏุงุชุง ุชุฌุฑูŠุจูŠุฉ ู†ู‚ุฏุฑ ู†ุนู…ู„ ุนู„ูŠู‡ุง queries. ู‡ู†ุณุชุฎุฏู… ุงู„ู€ Employee ูˆ Product lists ุงู„ู„ูŠ ุนู…ู„ู†ุงู‡ู… ููˆู‚ ูƒุฃู…ุซู„ุฉ.

ู‡ุชู„ุงู‚ูŠู‡ ู‡ู†ุง Data Setup for LINQ

(ู‡ู†ูุชุฑุถ ุฅู† ุงู„ุฏุงุชุง ุฏูŠ ู…ูˆุฌูˆุฏุฉ ููŠ ุจุงู‚ูŠ ุงู„ุฃู…ุซู„ุฉ)

Deferred Execution VS Immediate Execution

ุฏูŠ ู†ู‚ุทุฉ ู…ู‡ู…ุฉ ุฌุฏู‹ุง ููŠ ูู‡ู… LINQ ุจูŠุดุชุบู„ ุฅุฒุงูŠ.

1. Deferred Execution (ุงู„ุชู†ููŠุฐ ุงู„ู…ุคุฌู„)

  • ู…ุนุธู… LINQ operators (ุฒูŠ Where, Select, OrderBy, GroupBy, Join, ูˆุบูŠุฑู‡ุง ูƒุชูŠุฑ) ู…ุด ุจุชุชู†ูุฐ ุฃูˆู„ ู…ุง ุชูƒุชุจู‡ุง.
  • ู„ู…ุง ุจุชูƒุชุจ query ุจุงุณุชุฎุฏุงู… ุงู„ู€ operators ุฏูŠุŒ ุงู„ู„ูŠ ุจูŠุญุตู„ ุฅู† LINQ ุจูŠุณุฌู„ ุงู„ุฎุทูˆุงุช ุฃูˆ ุงู„ู€ expression ุจุชุงุน ุงู„ู€ query ุฏู‡ุŒ ูˆุจูŠุฏูŠู„ูƒ ูƒุฃู†ู‡ุง โ€œูˆุนุฏโ€ (Promise) ุฃูˆ ูˆุตูุฉ ู„ู„ุชู†ููŠุฐ.
  • ุงู„ู€ Query ู…ุด ุจูŠุชู†ูุฐ ูุนู„ูŠู‹ุง ุฅู„ุง ู„ู…ุง ุชูŠุฌูŠ ุชุทู„ุจ ุงู„ู†ุชูŠุฌุฉ ุจุชุงุนุชู‡. ุฅู…ุชู‰ ุจู†ุทู„ุจ ุงู„ู†ุชูŠุฌุฉุŸ
    • ู„ู…ุง ู†ุนู…ู„ loop ุนู„ู‰ ุงู„ู€ result ุจุงุณุชุฎุฏุงู… foreach.
    • ู„ู…ุง ู†ู†ุงุฏูŠ ุนู„ู‰ method ู…ู† ุงู„ู„ูŠ ุจุชุนู…ู„ Immediate Execution (ุฒูŠ ToList(), ToArray(), Count(), First(), Sum(), etc.).
  • ุนู„ู‰ ู…ุณุชูˆู‰ ุงู„ู€ MemoryุŒ ุงู„ู€ variable ุงู„ู„ูŠ ุจูŠุดูŠู„ ู†ุชูŠุฌุฉ ุงู„ู€ deferred query (ุฒูŠ evenNumbers ููŠ ุงู„ู…ุซุงู„ ุชุญุช) ุจูŠุฎุฒู† ุจุณ ุงู„ูˆุตูุฉ ุจุชุงุนุฉ ุงู„ู€ query ูˆุจูŠุญุชูุธ ุจู€ reference ู„ู„ู€ original list (ุฒูŠ numbers).
  • ู„ู…ุง ุชูŠุฌูŠ ุชุทู„ุจ ุงู„ู†ุชูŠุฌุฉ (ู…ุซู„ู‹ุง ุจู€ foreach)ุŒ ุณุงุนุชู‡ุง ุจุณ ุงู„ู€ query ุจูŠุฑูˆุญ ูŠุชู†ูุฐ ุนู„ู‰ ุงู„ู€ original list ููŠ ุงู„ูˆู‚ุช ุฏู‡ ุจุญุงู„ุชู‡ุง ุงู„ุญุงู„ูŠุฉ.

ู…ุซุงู„ ูŠูˆุถุญ ุงู„ู€ Deferred Execution:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 
// Define the query using Where (Deferred Execution operator)
var evenNumbersQuery = numbers.Where(n => n % 2 == 0);
// <<< Query is NOT executed yet! 'evenNumbersQuery' only holds the definition. >>>
 
Console.WriteLine("Modifying the list AFTER defining the query...");
numbers.Add(12); // Add a new even number
numbers.Add(14); // Add another new even number
numbers.Remove(4); // Remove an existing even number
 
Console.WriteLine("Iterating through the query result (Execution happens NOW):");
// The query executes here because we are asking for the results via foreach
foreach (var item in evenNumbersQuery)
{
    Console.Write(item + " "); // Output will include 12, 14 and exclude 4
}
Console.WriteLine();
// Expected output: 2 6 8 10 12 14

ู„ูŠู‡ ุงู„ู€ LINQ ุจุชุดุชุบู„ ุจุงู„ุทุฑูŠู‚ุฉ ุงู„ู…ุคุฌู„ุฉ ุฏูŠุŸ ุฅูŠู‡ ููˆุงูŠุฏู‡ุงุŸ

  1. ุงู„ู€ Performance (ุงู„ุฃุฏุงุก):
    • ุงู„ู€ Query ู…ุด ุจูŠุชู†ูุฐ ุฅู„ุง ู„ู…ุง ุชุญุชุงุฌู‡ ูุนู„ู‹ุง. ู„ูˆ ุนุฑูุช query ูˆู…ุนู…ู„ุชุด ุนู„ูŠู‡ loop ุฃูˆ ู…ุญูˆู„ุชู‡ูˆุด ู„ู€ ListุŒ ู…ุด ู‡ูŠุณุชู‡ู„ูƒ ุฃูŠ ูˆู‚ุช ุชู†ููŠุฐ ุชู‚ุฑูŠุจู‹ุง.
    • ู„ูˆ ุนู†ุฏูƒ query ุจูŠุฑุฌุน ุฏุงุชุง ูƒุชูŠุฑุŒ ูˆุงู†ุช ู…ุญุชุงุฌ ุจุณ ุฃูˆู„ ุนู†ุตุฑ (FirstOrDefault()) ุฃูˆ ุฃูˆู„ ูƒุงู… ุนู†ุตุฑ (Take(5)), ุงู„ู€ query ู‡ูŠุชู†ูุฐ ุจุณ ู„ุญุฏ ู…ุง ูŠุฌูŠุจ ุงู„ู…ุทู„ูˆุจ ูˆู…ุด ู‡ูŠูƒู…ู„ ุจุงู‚ูŠ ุงู„ุฏุงุชุง.
  2. ุงู„ู€ Memory Efficiency (ูƒูุงุกุฉ ุงู„ุฐุงูƒุฑุฉ):
    • ุงู„ู†ุชุงุฆุฌ ู…ุด ุจุชุชุฎุฒู† ููŠ ุงู„ู€ memory ูƒู„ู‡ุง ู…ุฑุฉ ูˆุงุญุฏุฉ (ุฅู„ุง ู„ูˆ ุทู„ุจุช ุฏู‡ ุจู€ ToList() ู…ุซู„ู‹ุง). ุฏู‡ ูƒูˆูŠุณ ุฌุฏู‹ุง ู„ูˆ ุจุชุชุนุงู…ู„ ู…ุน ุญุฌู… ุฏุงุชุง ูƒุจูŠุฑ ุฌุฏู‹ุง ู…ู…ูƒู† ู…ูŠูƒููŠุด ููŠ ุงู„ู€ memory.
  3. ุงู„ู€ Composability (ุงู„ุชุฑูƒูŠุจ):
    • ุชู‚ุฏุฑ ุชุจู†ูŠ query ู…ุนู‚ุฏ ุนู„ู‰ ู…ุฑุงุญู„. ู…ู…ูƒู† ุชุนุฑู query ุฃุณุงุณูŠุŒ ูˆุจุนุฏูŠู† ุชุถูŠู ุนู„ูŠู‡ filter ุชุงู†ูŠ (.Where(...)) ุฃูˆ ุชุฑุชูŠุจ (.OrderBy(...)) ุญุณุจ ุงู„ุญุงุฌุฉุŒ ูˆูƒู„ ุฏู‡ ู‡ูŠุชุฌู…ุน ูˆู‡ูŠุชุฑูƒุจ ู…ุน ุจุนุถ ูˆูŠุชู†ูุฐ ู…ุฑุฉ ูˆุงุญุฏุฉ ููŠ ุงู„ุขุฎุฑ.
  4. ุงู„ู€ Always Fresh Data (ุฏุงูŠู…ู‹ุง ุฃุญุฏุซ ุฏุงุชุง):
    • ุฒูŠ ู…ุง ุดูู†ุง ููŠ ุงู„ู…ุซุงู„ุŒ ู„ุฅู† ุงู„ู€ query ุจูŠุชู†ูุฐ ู„ู…ุง ุชุทู„ุจ ุงู„ู†ุชูŠุฌุฉุŒ ูู‡ูˆ ุฏุงูŠู…ู‹ุง ุจูŠุดุชุบู„ ุนู„ู‰ ุขุฎุฑ ู†ุณุฎุฉ ู…ู† ุงู„ุฏุงุชุง ุงู„ู„ูŠ ููŠ ุงู„ู€ source list. ู„ูˆ ุนุฏู„ุช ููŠ ุงู„ู€ list ุจุนุฏ ู…ุง ุนุฑูุช ุงู„ู€ query ูˆู‚ุจู„ ู…ุง ุชู†ูุฐู‡ุŒ ุงู„ุชุนุฏูŠู„ุงุช ุฏูŠ ู‡ุชู†ุนูƒุณ ููŠ ุงู„ู†ุชูŠุฌุฉ.
  5. ุงู„ู€ Working with potentially infinite sequences:
    • ู†ุธุฑูŠู‹ุงุŒ ู…ู…ูƒู† ุชุนู…ู„ query ุนู„ู‰ sequence ู…ุด ุจุชู†ุชู‡ูŠ (ู…ุซู„ู‹ุง generator function ุจุชุทู„ุน ุฃุฑู‚ุงู… ู„ู„ุฃุจุฏ)ุŒ ูˆุชุงุฎุฏ ู…ู†ู‡ุง ุฌุฒุก (Take(100)) ู…ู† ุบูŠุฑ ู…ุง ุชุญุชุงุฌ ุชุญู…ู„ ุงู„ู€ sequence ูƒู„ู‡ุง.

ุงู„ู€ Categories ุงู„ู„ูŠ ุจุชุดุชุบู„ Deferred Execution: ู…ุนุธู… ุงู„ู€ Categories (ุญูˆุงู„ูŠ 10 ู…ู† ุงู„ู€ 13) ุจุชุดุชุบู„ ุจุงู„ุทุฑูŠู‚ุฉ ุฏูŠุŒ ุฒูŠ:

  • Filtration (Where)
  • Projection (Select, SelectMany)
  • Ordering (OrderBy, ThenBy, Reverse)
  • Grouping (GroupBy)
  • Joining (Join, GroupJoin)
  • Set (Union, Intersect, Except, Distinct, Concat)
  • Partitioning (Take, Skip, TakeWhile, SkipWhile, Chunk)
  • Generation (Range, Repeat, Empty)
  • Zipping (Zip)

2. Immediate Execution (ุงู„ุชู†ููŠุฐ ุงู„ููˆุฑูŠ)

  • ุนู„ู‰ ุนูƒุณ ุงู„ู€ DeferredุŒ ููŠู‡ ุจุนุถ ุงู„ู€ LINQ operators ุจุชู†ูุฐ ุงู„ู€ query ููˆุฑู‹ุง ุฃูˆู„ ู…ุง ุชู†ุงุฏูŠ ุนู„ูŠู‡ุง.
  • ุงู„ู€ Operators ุฏูŠ ุบุงู„ุจู‹ุง ุจุชูƒูˆู† ุงู„ู„ูŠ:
    • ุจุชุฑุฌุน ู‚ูŠู…ุฉ ูˆุงุญุฏุฉ (single value) ู…ู† ุงู„ู€ sequence (ุฒูŠ Count(), Sum(), Max(), First(), ElementAt()).
    • ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู€ collection ุชุงู†ูŠุฉ ููŠ ุงู„ู€ memory (ุฒูŠ ToList(), ToArray(), ToDictionary(), ToHashSet()).
  • ู„ู…ุง ุจุชุณุชุฎุฏู… ูˆุงุญุฏ ู…ู† ุงู„ู€ operators ุฏูŠุŒ ุงู„ู€ query ุงู„ู„ูŠ ู‚ุจู„ู‡ (ู„ูˆ ููŠู‡) ุจูŠุชู†ูุฐ ูƒู„ู‡ ุนู„ุทูˆู„ุŒ ูˆุงู„ู†ุชูŠุฌุฉ ุจุชุชุญุณุจ ูˆุชุชุฎุฒู† ุฃูˆ ุชุชุฑุฌุน.

ู…ุซุงู„ ูŠูˆุถุญ ุงู„ู€ Immediate Execution:

List<int> numbers2 = new List<int> { 1, 2, 3, 4, 5 };
 
// Define the query AND execute it immediately using ToList()
List<int> evenNumbersList = numbers2.Where(n => n % 2 == 0).ToList();
// <<< Query executed NOW! 'evenNumbersList' holds [2, 4] in memory. >>>
 
Console.WriteLine("\nModifying the list AFTER immediate execution...");
numbers2.Add(6); // Add a new even number
numbers2.Add(8); // Add another new even number
 
Console.WriteLine("Iterating through the immediate result list:");
// We are iterating through the list created earlier, not re-executing the query
foreach (var item in evenNumbersList)
{
    Console.Write(item + " "); // Output will only be the numbers captured initially
}
Console.WriteLine();
// Expected output: 2 4

ุงู„ูุฑู‚ ุจูŠู† ุงู„ู€ Deferred ูˆุงู„ู€ Immediate ุจุงุฎุชุตุงุฑ:

  • ุงู„ู€ Deferred:
    • ุงู„ุชู†ููŠุฐ ุจูŠุชุฃุฌู„ ู„ุญุฏ ู…ุง ุชุทู„ุจ ุงู„ู†ุชูŠุฌุฉ (foreach, ToList(), etc.).
    • ุงู„ู†ุชูŠุฌุฉ ุฏุงูŠู…ู‹ุง ุจุชุนูƒุณ ุขุฎุฑ ุญุงู„ุฉ ู„ู„ุฏุงุชุง.
    • ุฃู…ุซู„ุฉ: Where(), Select(), OrderBy().
  • ุงู„ู€ Immediate:
    • ุงู„ุชู†ููŠุฐ ุจูŠุญุตู„ ููˆุฑู‹ุง ุฃูˆู„ ู…ุง ุชู†ุงุฏูŠ ุงู„ู€ operator.
    • ุงู„ู†ุชูŠุฌุฉ ุจุชุชุญุณุจ ูˆุชุชุฎุฒู† (ู„ูˆ ToList ู…ุซู„ู‹ุง) ุฃูˆ ุชุชุฑุฌุน (ู„ูˆ Count ู…ุซู„ู‹ุง).
    • ุฃูŠ ุชุนุฏูŠู„ุงุช ุนู„ู‰ ุงู„ุฏุงุชุง ุงู„ุฃุตู„ูŠุฉ ุจุนุฏ ุงู„ุชู†ููŠุฐ ู…ุด ุจุชุฃุซุฑ ุนู„ู‰ ุงู„ู†ุชูŠุฌุฉ ุงู„ู„ูŠ ุงุชุญุณุจุช ุฎู„ุงุต.
    • ุฃู…ุซู„ุฉ: ToList(), ToArray(), Count(), First(), Sum().

ุฅู…ุชู‰ ู†ุณุชุฎุฏู… ุงู„ู€ Immediate ExecutionุŸ

  • ู„ู…ุง ุชูƒูˆู† ุนุงูŠุฒ ุชุญูุธ โ€œู„ู‚ุทุฉโ€ (snapshot) ู…ู† ู†ุชูŠุฌุฉ ุงู„ู€ query ููŠ ู„ุญุธุฉ ู…ุนูŠู†ุฉุŒ ูˆู…ุด ุนุงูŠุฒู‡ุง ุชุชุฃุซุฑ ุจุฃูŠ ุชุบูŠูŠุฑุงุช ู‡ุชุญุตู„ ุจุนุฏ ูƒุฏู‡ ููŠ ุงู„ุฏุงุชุง ุงู„ุฃุตู„ูŠุฉ.
  • ู„ู…ุง ุชูƒูˆู† ู‡ุชุณุชุฎุฏู… ู†ุชูŠุฌุฉ ุงู„ู€ query ุฏู‡ ูƒุฐุง ู…ุฑุฉ ููŠ ุงู„ูƒูˆุฏ ุจุชุงุนูƒุŒ ูุชุญูˆูŠู„ู‡ุง ู„ู€ List ุฃูˆ Array ู…ุฑุฉ ูˆุงุญุฏุฉ ู…ู…ูƒู† ูŠูƒูˆู† ุฃูƒูุฃ ู…ู† ุฅุนุงุฏุฉ ุชู†ููŠุฐ ุงู„ู€ query ูƒู„ ู…ุฑุฉ.
  • ู„ู…ุง ุชูƒูˆู† ุงู„ู†ุชูŠุฌุฉ ุงู„ู†ู‡ุงุฆูŠุฉ ู„ู„ู€ query ู‡ูŠ ู‚ูŠู…ุฉ ูˆุงุญุฏุฉ (ุฒูŠ ุนุฏุฏ ุงู„ุนู†ุงุตุฑ ุฃูˆ ู…ุฌู…ูˆุนู‡ู…).

ุงู„ู€ Categories ุงู„ู„ูŠ ุจุชุดุชุบู„ Immediate Execution:

ููŠู‡ 3 Categories ุฃุณุงุณูŠุฉ ุจุชุดุชุบู„ ุจุงู„ุทุฑูŠู‚ุฉ ุฏูŠ:

  1. ุงู„ู€ Element Operators ุงู„ู„ูŠ ุจุชุฌูŠุจ ุนู†ุตุฑ ูˆุงุญุฏ (ุฒูŠ First, Last, Single, ElementAt ูˆู…ุดุชู‚ุงุชู‡ู…).
  2. ุงู„ู€Aggregate Operator ุงู„ู„ูŠ ุจุชุนู…ู„ ุนู…ู„ูŠุงุช ุญุณุงุจูŠุฉ ุฃูˆ ุชุฌู…ูŠุนูŠุฉ ุนู„ู‰ ูƒู„ ุงู„ู€ sequence ุนุดุงู† ุชุฑุฌุน ู‚ูŠู…ุฉ ูˆุงุญุฏุฉ (ุฒูŠ Count, Sum, Average, Min, Max, Aggregate, Any, All).
  3. ุงู„ู€Casting Operators ุงู„ู„ูŠ ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู†ูˆุน collection ุชุงู†ูŠ (ุฒูŠ ToList, ToArray, ToDictionary, ToLookup, ToHashSet).

ู…ู„ุญูˆุธุฉ: ู„ูˆ ุนุงูŠุฒ ุชุฌุจุฑ query ู…ุนู…ูˆู„ ุจู€ deferred operators ุฅู†ู‡ ูŠุชู†ูุฐ ููˆุฑู‹ุงุŒ ู…ู…ูƒู† ุชุถูŠู ููŠ ุขุฎุฑู‡ operator ู…ู† ุจุชูˆุน ุงู„ู€ immediate execution (ุฒูŠ .ToList()).

LINQ (LINQ Operations / Operators)

ุฒูŠ ู…ุง ู‚ู„ู†ุงุŒ LINQ ููŠู‡ ุฃูƒุชุฑ ู…ู† 40 operator ู…ุชู‚ุณู…ูŠู† ู„ู€ 13 category. ุงุชูƒู„ู…ู†ุง ููˆู‚ ุนู† ุฃูˆู„ category ุงู„ู„ูŠ ู‡ูˆ ุงู„ู€ Filtration Operators ูˆูƒุงู† ุฃู‡ู… ูˆุงุญุฏ ููŠู‡ ู‡ูˆ Where.

ู‡ู†ุงุฎุฏ ุฏู„ูˆู‚ุชูŠ ุจุงู‚ูŠ ุงู„ู€ categories ุงู„ู…ุดู‡ูˆุฑุฉ ูˆุงู„ู…ู‡ู…ุฉ:

1. Projection or Transformation Operators (ุชุญูˆูŠู„ ุงู„ุดูƒู„)

ุงู„ู€ Operators ุฏูŠ ุจุชุงุฎุฏ ูƒู„ ุนู†ุตุฑ ููŠ ุงู„ู€ sequence ุงู„ุฃุตู„ูŠุฉ ูˆุชุญูˆู„ู‡ ู„ุดูƒู„ ุชุงู†ูŠ ุฃูˆ ุชุฎุชุงุฑ ุฌุฒุก ู…ู†ู‡. ุฃุดู‡ุฑู‡ู… Select ูˆ SelectMany. (ุฏูˆู„ Deferred Execution).

Select()

  • ุจุชุงุฎุฏ ูƒู„ ุนู†ุตุฑ ููŠ ุงู„ู€ collection ูˆุชุญูˆู„ู‡ ู„ุญุงุฌุฉ ุชุงู†ูŠุฉ (ู…ู…ูƒู† ุชูƒูˆู† property ู…ุนูŠู†ุฉ ู…ู† ุงู„ุนู†ุตุฑุŒ ุฃูˆ object ุฌุฏูŠุฏ ุฎุงู„ุต).
  • ุจุชุฑุฌุน sequence ุฌุฏูŠุฏุฉ ุจู†ูุณ ุญุฌู… ุงู„ู€ sequence ุงู„ุฃุตู„ูŠุฉุŒ ุจุณ ุงู„ุนู†ุงุตุฑ ุงู„ู„ูŠ ุฌูˆุงู‡ุง ุดูƒู„ู‡ุง ู…ุชุบูŠุฑ.

ู…ุซุงู„: ุงุฎุชูŠุงุฑ ุฃุณู…ุงุก ุงู„ู…ูˆุธููŠู† ุจุณ:

// Select just the names of the employees
var employeeNames = employees.Select(employee => employee.Name);
// employeeNames is now an IEnumerable<string>
 
Console.WriteLine("\nEmployee Names (Select):");
foreach (var name in employeeNames)
{
    Console.WriteLine(name);
}
 
// Query Syntax equivalent:
var employeeNamesQuery = from e in employees
                         select e.Name;

ู…ุซุงู„: ุงุฎุชูŠุงุฑ ุฃูƒุชุฑ ู…ู† property (ุจุงุณุชุฎุฏุงู… Anonymous Type):

ู…ูŠู†ูุนุด ุฃุฑุฌุน ุฃูƒุชุฑ ู…ู† property ู…ุจุงุดุฑุฉ ุจู€ Select. ู„ูˆ ุนุงูŠุฒ ุฃุฑุฌุน ู…ุซู„ู‹ุง ุงุณู… ูˆุนู…ุฑ ุงู„ู…ูˆุธูุŒ ู„ุงุฒู… ุฃุฑุฌุนู‡ู… ููŠ object ุฌุฏูŠุฏ.

ุงู„ุญู„ ุงู„ุณู‡ู„ ูˆุงู„ู…ุจุงุดุฑ ู‡ู†ุง ู‡ูˆ ุงุณุชุฎุฏุงู… Anonymous Type:

// Select Name and Age into an Anonymous Type
var nameAndAge = employees.Select(e => new { EmployeeName = e.Name, EmployeeAge = e.Salary }); // Assuming Salary represents Age for example
// nameAndAge is now an IEnumerable of objects with Name and Age properties
 
Console.WriteLine("\nEmployee Name and Age (Select with Anonymous Type):");
foreach (var item in nameAndAge)
{
    Console.WriteLine($"Name: {item.EmployeeName}, Age: {item.EmployeeAge}");
    // You can access properties by the names you gave them (EmployeeName, EmployeeAge)
}
 
// Using aliases for shorter names in the anonymous type:
var nameAndAgeShorter = employees.Select(e => new { N = e.Name, A = e.Salary });
foreach (var item in nameAndAgeShorter)
{
    Console.WriteLine($"N: {item.N}, A: {item.A}");
}
 
 
// Query Syntax equivalent for Anonymous Type:
var nameAndAgeQuery = from e in employees
                      select new // Create anonymous type
                      {
                          EmployeeName = e.Name,
                          EmployeeAge = e.Salary
                      };
  • ุงู„ู€ Anonymous Type ุฏู‡ type ู…ู„ูˆุด ุงุณู… ุจู†ุนุฑูู‡ ููŠ ุงู„ูƒูˆุฏุŒ ุงู„ู€ CLR ู‡ูˆ ุงู„ู„ูŠ ุจูŠุนู…ู„ู‡ ููŠ ุงู„ู€ runtime.
  • ู„ูˆ ุนุงูŠุฒ ุชุนู…ู„ assign ู„ู€ variable ููŠู‡ anonymous type ู„ู€ variable ุชุงู†ูŠุŒ ู„ุงุฒู… ุงู„ู€ properties ุชูƒูˆู† ุจู†ูุณ ุงู„ุฃุณู…ุงุก ูˆุงู„ู€ types ูˆุงู„ุชุฑุชูŠุจ ุจุงู„ุธุจุท.

Indexed Select:

ุฒูŠ ุงู„ู€ Indexed WhereุŒ ููŠู‡ overload ู„ู€ Select ุจูŠุงุฎุฏ ุงู„ู€ index ูƒู€ parameter ุชุงู†ูŠ. ู…ุชุงุญ ุจุณ ููŠ ุงู„ู€ Fluent Syntax.

// Select Name along with its index in the original list
var namesWithIndex = employees.Select((emp, index) => new { Index = index, Name = emp.Name });
 
Console.WriteLine("\nNames with Index (Indexed Select):");
foreach (var item in namesWithIndex)
{
    Console.WriteLine($"Index: {item.Index}, Name: {item.Name}");
}

SelectMany()

  • ุฏูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ู„ู…ุง ูŠูƒูˆู† ุนู†ุฏู†ุง sequence of sequences (ูŠุนู†ูŠ ู…ุซู„ู‹ุง List ุฌูˆุงู‡ุง List ุชุงู†ูŠุฉ) ูˆุนุงูŠุฒูŠู† ู†ุนู…ู„ู‡ุง โ€œูุฑุฏโ€ ุฃูˆ โ€œุชุณุทูŠุญโ€ (Flattening) ุนุดุงู† ุชุจู‚ู‰ sequence ูˆุงุญุฏุฉ ุจุณ.
  • ุชุฎูŠู„ ุนู†ุฏูƒ ู„ูŠุณุชุฉ ู…ูˆุธููŠู†ุŒ ูˆูƒู„ ู…ูˆุธู ุนู†ุฏู‡ ู„ูŠุณุชุฉ ุจุงู„ู…ู‡ุงุฑุงุช (Skills) ุจุชุงุนุชู‡. ู„ูˆ ุนุงูŠุฒ ุชุฌูŠุจ ูƒู„ ุงู„ู…ู‡ุงุฑุงุช ุงู„ู…ูˆุฌูˆุฏุฉ ุนู†ุฏ ูƒู„ ุงู„ู…ูˆุธููŠู† ููŠ ู„ูŠุณุชุฉ ูˆุงุญุฏุฉุŒ ู‡ู†ุง ุจู†ุณุชุฎุฏู… SelectMany.

ู…ุซุงู„:

// Assume Employee class has a List<string> Skills property
public class EmployeeWithSkills
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<string> Skills { get; set; }
    public override string ToString() => $"Id: {Id}, Name: {Name}, Skills: {string.Join(", ", Skills)}";
}
 
List<EmployeeWithSkills> employeesWithSkills = new List<EmployeeWithSkills>
{
    new EmployeeWithSkills { Id = 1, Name = "Ahmed", Skills = new List<string> { "C#", "SQL", "ASP.NET" } },
    new EmployeeWithSkills { Id = 2, Name = "Mona", Skills = new List<string> { "HTML", "CSS", "JavaScript" } },
    new EmployeeWithSkills { Id = 3, Name = "Ali", Skills = new List<string> { "C#", "Azure", "Docker" } },
    new EmployeeWithSkills { Id = 4, Name = "Sara", Skills = new List<string> { "JavaScript", "React", "Node.js" } }
};
 
// Using SelectMany to get a single list of all skills
var allSkills = employeesWithSkills.SelectMany(emp => emp.Skills);
// allSkills is now IEnumerable<string> containing all skills from all employees
 
Console.WriteLine("\nAll Skills (SelectMany):");
Console.WriteLine(string.Join(", ", allSkills));
// Output: C#, SQL, ASP.NET, HTML, CSS, JavaScript, C#, Azure, Docker, JavaScript, React, Node.js
 
// If you want only unique skills, combine SelectMany with Distinct
var uniqueSkills = employeesWithSkills.SelectMany(emp => emp.Skills).Distinct();
Console.WriteLine("\nUnique Skills (SelectMany + Distinct):");
Console.WriteLine(string.Join(", ", uniqueSkills));
// Output: C#, SQL, ASP.NET, HTML, CSS, JavaScript, Azure, Docker, React, Node.js
 
// Query Syntax equivalent for SelectMany:
// Uses multiple 'from' clauses
var allSkillsQuery = from emp in employeesWithSkills // Outer loop for employees
                     from skill in emp.Skills     // Inner loop for skills within each employee
                     select skill;                // Select the skill
Console.WriteLine("\nAll Skills (Query Syntax):");
Console.WriteLine(string.Join(", ", allSkillsQuery));
 
var uniqueSkillsQuery = (from emp in employeesWithSkills
                         from skill in emp.Skills
                         select skill).Distinct(); // Add Distinct for unique
Console.WriteLine("\nUnique Skills (Query Syntax + Distinct):");
Console.WriteLine(string.Join(", ", uniqueSkillsQuery));
 

ุงู„ูุฑู‚ ุจูŠู† Select ูˆ SelectMany ููŠ ุงู„ุญุงู„ุฉ ุฏูŠ:

ู„ูˆ ูƒู†ุช ุงุณุชุฎุฏู…ุช Select ุจุฏู„ SelectMany ููŠ ุงู„ู…ุซุงู„ ุจุชุงุน ุงู„ู…ู‡ุงุฑุงุช:

var skillsUsingSelect = employeesWithSkills.Select(emp => emp.Skills);
// skillsUsingSelect is IEnumerable<List<string>> (a list of lists)
 
Console.WriteLine("\nSkills using Select (Incorrect for flattening):");
foreach (var skillList in skillsUsingSelect)
{
    // This will print the default ToString() of List<string>, not the skills themselves
    Console.WriteLine(skillList);
    // Example output line: System.Collections.Generic.List`1[System.String]
}

ุงู„ู€Select ู‡ุชุฑุฌุนู„ูƒ sequence ู…ู† ู†ูˆุน List<string> (ู„ูŠุณุชุฉ ุงู„ู„ูŠุณุชุงุช)ุŒ ู…ุด ู„ูŠุณุชุฉ ูˆุงุญุฏุฉ ููŠู‡ุง ูƒู„ ุงู„ู€ strings. ุนุดุงู† ูƒุฏู‡ SelectMany ู‡ูŠ ุงู„ู…ู†ุงุณุจุฉ ููŠ ุญุงู„ุฉ ุงู„ู€ Flattening.

2. Ordering Operators (ุชุฑุชูŠุจ ุงู„ุนู†ุงุตุฑ)

ุงู„ู€ Operators ุฏูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ุนุดุงู† ู†ุฑุชุจ ุนู†ุงุตุฑ ุงู„ู€ sequence ุจู†ุงุกู‹ ุนู„ู‰ property ู…ุนูŠู†ุฉ ุฃูˆ ุฃูƒุชุฑ. (ุฏูˆู„ Deferred Execution).

OrderBy()

  • ุจุชุฑุชุจ ุงู„ุนู†ุงุตุฑ ุชุตุงุนุฏูŠู‹ุง (Ascending) (ู…ู† ุงู„ุตุบูŠุฑ ู„ู„ูƒุจูŠุฑุŒ ุฃูˆ ุฃุจุฌุฏูŠู‹ุง ู„ู„ู€ strings).
// Order employees by Salary (ascending)
var sortedBySalaryAsc = employees.OrderBy(emp => emp.Salary);
 
Console.WriteLine("\nEmployees Sorted by Salary (Ascending):");
foreach (var emp in sortedBySalaryAsc)
{
    Console.WriteLine(emp);
}
 
// Query Syntax equivalent:
var sortedBySalaryAscQuery = from e in employees
                             orderby e.Salary // 'ascending' is the default
                             select e;

OrderByDescending()

  • ุจุชุฑุชุจ ุงู„ุนู†ุงุตุฑ ุชู†ุงุฒู„ูŠู‹ุง (Descending) (ู…ู† ุงู„ูƒุจูŠุฑ ู„ู„ุตุบูŠุฑ).
// Order employees by Salary (descending)
var sortedBySalaryDesc = employees.OrderByDescending(emp => emp.Salary);
 
Console.WriteLine("\nEmployees Sorted by Salary (Descending):");
foreach (var emp in sortedBySalaryDesc)
{
    Console.WriteLine(emp);
}
 
// Query Syntax equivalent:
var sortedBySalaryDescQuery = from e in employees
                              orderby e.Salary descending
                              select e;

ThenBy() / ThenByDescending()

  • ุจู†ุณุชุฎุฏู…ู‡ู… ุจุนุฏ OrderBy ุฃูˆ OrderByDescending ุนุดุงู† ู†ุนู…ู„ ุชุฑุชูŠุจ ุซุงู†ูˆูŠ (secondary sort).
  • ูŠุนู†ูŠ ู„ูˆ ููŠู‡ ุนู†ุตุฑูŠู† ู„ูŠู‡ู… ู†ูุณ ุงู„ู‚ูŠู…ุฉ ููŠ ุงู„ุชุฑุชูŠุจ ุงู„ุฃูˆู„ (ู…ุซู„ู‹ุง ุงุชู†ูŠู† ู…ูˆุธููŠู† ู„ูŠู‡ู… ู†ูุณ ุงู„ู…ุฑุชุจ)ุŒ ู†ุณุชุฎุฏู… ThenBy ุนุดุงู† ู†ุฑุชุจู‡ู… ุชุงู†ูŠ ุจู†ุงุกู‹ ุนู„ู‰ property ุชุงู†ูŠุฉ (ู…ุซู„ู‹ุง ู†ุฑุชุจู‡ู… ุฃุจุฌุฏูŠู‹ุง ุจุงู„ุงุณู…).
// Order by Gender (asc), then by Name (asc) for those with the same gender
var sortedByGenderThenName = employees
    .OrderBy(emp => emp.Gender)
    .ThenBy(emp => emp.Name);
 
Console.WriteLine("\nEmployees Sorted by Gender (Asc) then Name (Asc):");
foreach (var emp in sortedByGenderThenName)
{
    Console.WriteLine(emp);
}
 
// You can also use ThenByDescending
var sortedBySalaryDescThenNameAsc = employees
    .OrderByDescending(emp => emp.Salary) // Highest salary first
    .ThenBy(emp => emp.Name);             // If salaries are equal, sort by name A-Z
 
// Query Syntax equivalent (comma separates the sorting criteria):
var sortedQuery = from e in employees
                  orderby e.Gender, e.Name // Primary sort by Gender, Secondary by Name
                  select e;
 
var sortedQuery2 = from e in employees
                   orderby e.Salary descending, e.Name ascending // Can mix ascending/descending
                   select e;
 

Reverse()

  • ุฏูŠ ู…ุด ุจุชุนู…ู„ sort ุจู…ุนู†ู‰ ุงู„ูƒู„ู…ุฉุŒ ู‡ูŠ ุจุณ ุจุชุนูƒุณ ุชุฑุชูŠุจ ุงู„ุนู†ุงุตุฑ ููŠ ุงู„ู€ sequence ุฒูŠ ู…ุง ู‡ูŠ.
// Reverse the original order of the list
// Note: Reverse() modifies the list in-place if it's a List<T>,
// but the LINQ Reverse() extension method returns a new reversed IEnumerable
// without modifying the original source IF the source is not a List/Array.
// For safety, let's apply it to a query result or a copy if needed.
 
var reversedOrder = employees.AsEnumerable().Reverse(); // Apply to IEnumerable view
 
Console.WriteLine("\nEmployees in Reversed Original Order:");
foreach (var emp in reversedOrder)
{
    Console.WriteLine(emp);
}
// Note: Query Syntax does not have a direct equivalent for Reverse().

3. Element Operators (ุงุฎุชูŠุงุฑ ุนู†ุตุฑ ู…ุญุฏุฏ)

ุงู„ู€ Operators ุฏูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ุนุดุงู† ู†ุฌูŠุจ ุนู†ุตุฑ ูˆุงุญุฏ ุจุณ ู…ู† ุงู„ู€ sequence ุจู†ุงุกู‹ ุนู„ู‰ ู…ูˆู‚ุนู‡ ุฃูˆ ุดุฑุท ู…ุนูŠู†.

  • ู…ู‡ู… ุฌุฏู‹ุง: ูƒู„ ุงู„ู€ Operators ููŠ ุงู„ู€ Category ุฏูŠ ุจุชุนู…ู„ Immediate Execution (ุชู†ููŠุฐ ููˆุฑูŠ).
  • ู…ู‡ู… ุฌุฏู‹ุง: ู…ุนุธู…ู‡ู… ู…ุชุงุญูŠู† ุจุณ ูƒู€ Fluent Syntax (ุฃูˆ ู…ู…ูƒู† ุชุณุชุฎุฏู… Hybrid Syntax).

ุงู„ู€ Operators ุงู„ุฃุณุงุณูŠุฉ ูˆู…ู‚ุงุฑู†ุชู‡ุง:

Operatorุงู„ูˆุตูู„ูˆ ุงู„ู€ Sequence ูุงุถูŠุฉุŸู„ูˆ ููŠู‡ ุฃูƒุชุฑ ู…ู† ุนู†ุตุฑ ุจูŠุญู‚ู‚ ุงู„ุดุฑุทุŸู„ูˆ ู…ููŠุด ูˆู„ุง ุนู†ุตุฑ ุจูŠุญู‚ู‚ ุงู„ุดุฑุทุŸ
First()ุจูŠุฑุฌุน ุฃูˆู„ ุนู†ุตุฑ.ExceptionุจูŠุฑุฌุน ุฃูˆู„ ูˆุงุญุฏ ูŠู‚ุงุจู„ู‡Exception (ู„ูˆ ููŠู‡ ุดุฑุท)
FirstOrDefault()ุจูŠุฑุฌุน ุฃูˆู„ ุนู†ุตุฑุŒ ุฃูˆ ุงู„ู‚ูŠู…ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ (null ู„ู„ู€ reference typesุŒ 0 ู„ู„ู€ intุŒ false ู„ู„ู€ boolโ€ฆ).ุจูŠุฑุฌุน DefaultุจูŠุฑุฌุน ุฃูˆู„ ูˆุงุญุฏ ูŠู‚ุงุจู„ู‡ุจูŠุฑุฌุน Default (ู„ูˆ ููŠู‡ ุดุฑุท)
Last()ุจูŠุฑุฌุน ุขุฎุฑ ุนู†ุตุฑ.ExceptionุจูŠุฑุฌุน ุขุฎุฑ ูˆุงุญุฏ ูŠู‚ุงุจู„ู‡Exception (ู„ูˆ ููŠู‡ ุดุฑุท)
LastOrDefault()ุจูŠุฑุฌุน ุขุฎุฑ ุนู†ุตุฑุŒ ุฃูˆ ุงู„ู‚ูŠู…ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ.ุจูŠุฑุฌุน DefaultุจูŠุฑุฌุน ุขุฎุฑ ูˆุงุญุฏ ูŠู‚ุงุจู„ู‡ุจูŠุฑุฌุน Default (ู„ูˆ ููŠู‡ ุดุฑุท)
Single()ุจูŠุฑุฌุน ุงู„ุนู†ุตุฑ ุงู„ูˆุญูŠุฏ.ExceptionExceptionException
SingleOrDefault()ุจูŠุฑุฌุน ุงู„ุนู†ุตุฑ ุงู„ูˆุญูŠุฏุŒ ุฃูˆ ุงู„ู‚ูŠู…ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ ู„ูˆ ูุงุถูŠุฉ.ุจูŠุฑุฌุน DefaultExceptionุจูŠุฑุฌุน Default
ElementAt(index)ุจูŠุฑุฌุน ุงู„ุนู†ุตุฑ ุนู†ุฏ ูู‡ุฑุณ (index) ู…ุนูŠู† (ุจูŠุจุฏุฃ ู…ู† 0).Exception (ู„ูˆ index ุบู„ุท)N/AException (ู„ูˆ index ุบู„ุท)
ElementAtOrDefault(index)ุจูŠุฑุฌุน ุงู„ุนู†ุตุฑ ุนู†ุฏ ูู‡ุฑุณ (index) ู…ุนูŠู†ุŒ ุฃูˆ ุงู„ู‚ูŠู…ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ ู„ูˆ ุงู„ู€ index ุบู„ุท (ุฎุงุฑุฌ ุงู„ู†ุทุงู‚).ุจูŠุฑุฌุน Default (ู„ูˆ index ุบู„ุท)N/AุจูŠุฑุฌุน Default (ู„ูˆ index ุบู„ุท)

ุฃู…ุซู„ุฉ:

  • ูƒู„ operator ู…ู† ุฏูˆู„ (ู…ุง ุนุฏุง ElementAt/OrDefault) ู„ูŠู‡ overload ุชุงู†ูŠ ุจูŠุงุฎุฏ predicate (ุดุฑุท) ุนุดุงู† ูŠู„ุงู‚ูŠ ุฃูˆู„/ุขุฎุฑ/ูˆุญูŠุฏ ุนู†ุตุฑ ุจูŠุญู‚ู‚ ุงู„ุดุฑุท ุฏู‡.
  • ุงู„ู€ OrDefault versions (ุฒูŠ FirstOrDefault, LastOrDefault, SingleOrDefault, ElementAtOrDefault) ู„ูŠู‡ู… overload ุชุงู†ูŠ (ููŠ ุจุนุถ ุงู„ู€ versions ุงู„ุฌุฏูŠุฏุฉ ู…ู† .NET) ุจูŠุณู…ุญู„ูƒ ุชุญุฏุฏ ุงู„ู‚ูŠู…ุฉ ุงู„ู€ default ุงู„ู„ูŠ ุชุฑุฌุน ุจุฏู„ ุงู„ู€ default ุจุชุงุน ุงู„ู€ type.
Console.WriteLine("\n--- Element Operators ---");
 
// First
try
{
    var firstEmployee = employees.First(); // Gets the first employee (Ahmed)
    Console.WriteLine($"First Employee: {firstEmployee.Name}");
    var firstFemale = employees.First(e => e.Gender == "Female"); // Gets the first female (Mona)
    Console.WriteLine($"First Female Employee: {firstFemale.Name}");
    // var nonExistent = employees.First(e => e.Salary > 10000); // Throws Exception
}
catch (Exception ex) { Console.WriteLine($"First() Exception: {ex.Message}"); }
 
// FirstOrDefault
var firstEmpOrDefault = employees.FirstOrDefault(); // Gets Ahmed
Console.WriteLine($"FirstOrDefault Employee: {firstEmpOrDefault?.Name}");
var firstFemaleOrDefault = employees.FirstOrDefault(e => e.Gender == "Female"); // Gets Mona
Console.WriteLine($"FirstOrDefault Female: {firstFemaleOrDefault?.Name}");
var nonExistentOrDefault = employees.FirstOrDefault(e => e.Salary > 10000); // Returns null
Console.WriteLine($"FirstOrDefault NonExistent (>10k Salary): {nonExistentOrDefault?.Name ?? "null"}");
// Example with custom default (might require newer .NET or specific package)
// var customDefault = employees.FirstOrDefault(e => e.Salary > 10000, new Employee { Name = "Default Emp" });
 
// Last
try
{
    var lastEmployee = employees.Last(); // Gets the last employee added (depends on list init)
    Console.WriteLine($"Last Employee: {lastEmployee.Name}");
    var lastMale = employees.Last(e => e.Gender == "Male"); // Gets the last male (Ali)
    Console.WriteLine($"Last Male Employee: {lastMale.Name}");
}
catch (Exception ex) { Console.WriteLine($"Last() Exception: {ex.Message}"); }
 
 
// LastOrDefault
var lastOrDefaultEmp = employees.LastOrDefault();
Console.WriteLine($"LastOrDefault Employee: {lastOrDefaultEmp?.Name}");
var lastOrDefaultNonExistent = employees.LastOrDefault(e => e.Address == "Mars"); // Returns null
Console.WriteLine($"LastOrDefault NonExistent (Mars): {lastOrDefaultNonExistent?.Name ?? "null"}");
 
// Single (Use when you expect EXACTLY ONE result)
try
{
    // var singleEmp = employees.Single(); // Throws Exception (more than one employee)
    var singleAli = employees.Single(e => e.Name == "Ali"); // Gets Ali (assuming name is unique)
    Console.WriteLine($"Single Employee (Ali): {singleAli.Name}");
    // var singleFemale = employees.Single(e => e.Gender == "Female"); // Throws Exception (more than one female)
    // var singleNonExistent = employees.Single(e => e.Salary > 10000); // Throws Exception (none found)
}
catch (Exception ex) { Console.WriteLine($"Single() Exception: {ex.Message}"); }
 
// SingleOrDefault (Use when you expect ZERO or ONE result)
try
{
    // var singleOrDefaultEmp = employees.SingleOrDefault(); // Throws Exception (more than one employee)
    var singleOrDefaultAli = employees.SingleOrDefault(e => e.Name == "Ali"); // Gets Ali
    Console.WriteLine($"SingleOrDefault Employee (Ali): {singleOrDefaultAli?.Name}");
    var singleOrDefaultNonExistent = employees.SingleOrDefault(e => e.Salary > 10000); // Returns null (zero found)
    Console.WriteLine($"SingleOrDefault NonExistent (>10k Salary): {singleOrDefaultNonExistent?.Name ?? "null"}");
    // var singleOrDefaultFemale = employees.SingleOrDefault(e => e.Gender == "Female"); // Throws Exception (more than one female)
}
catch (Exception ex) { Console.WriteLine($"SingleOrDefault() Exception: {ex.Message}"); }
 
 
// ElementAt
try
{
    var secondEmployee = employees.ElementAt(1); // Gets the employee at index 1 (Mona)
    Console.WriteLine($"ElementAt(1): {secondEmployee.Name}");
    // var outOfBounds = employees.ElementAt(100); // Throws Exception
}
catch (Exception ex) { Console.WriteLine($"ElementAt() Exception: {ex.Message}"); }
 
// ElementAtOrDefault
var secondEmpOrDefault = employees.ElementAtOrDefault(1); // Gets Mona
Console.WriteLine($"ElementAtOrDefault(1): {secondEmpOrDefault?.Name}");
var outOfBoundsOrDefault = employees.ElementAtOrDefault(100); // Returns null
Console.WriteLine($"ElementAtOrDefault(100): {outOfBoundsOrDefault?.Name ?? "null"}");

4. Aggregate Operators (ุชุฌู…ูŠุน ูˆุญุณุงุจ)

ุงู„ู€ Operators ุฏูŠ ุจุชุดุชุบู„ ุนู„ู‰ ุงู„ู€ sequence ูƒู„ู‡ุง ุนุดุงู† ุชุฑุฌุน ู‚ูŠู…ุฉ ูˆุงุญุฏุฉ ูƒู†ุชูŠุฌุฉ ู„ุนู…ู„ูŠุฉ ุญุณุงุจูŠุฉ ุฃูˆ ุชุฌู…ูŠุนูŠุฉ. ุฃุดู‡ุฑู‡ู… 7 ุชู‚ุฑูŠุจู‹ุง. (ุฏูˆู„ Immediate Execution).

Operatorุงู„ูˆุตู
Sum()ุจูŠุฑุฌุน ู…ุฌู…ูˆุน ู‚ูŠู… ุฑู‚ู…ูŠุฉ ููŠ ุงู„ู€ sequence.
Min()ุจูŠุฑุฌุน ุฃู‚ู„ ู‚ูŠู…ุฉ ููŠ ุงู„ู€ sequence.
Max()ุจูŠุฑุฌุน ุฃุนู„ู‰ ู‚ูŠู…ุฉ ููŠ ุงู„ู€ sequence.
Average()ุจูŠุฑุฌุน ุงู„ู…ุชูˆุณุท ุงู„ุญุณุงุจูŠ ู„ู‚ูŠู… ุฑู‚ู…ูŠุฉ.
Count()ุจูŠุฑุฌุน ุนุฏุฏ ุงู„ุนู†ุงุตุฑ ููŠ ุงู„ู€ sequence.
LongCount()ุฒูŠ Count ุจุณ ุจูŠุฑุฌุน long (ู„ูˆ ุงู„ุนุฏุฏ ูƒุจูŠุฑ ุฃูˆูŠ).
Aggregate()ุจูŠุนู…ู„ ุนู…ู„ูŠุฉ ุชุฌู…ูŠุนูŠุฉ ู…ุฎุตุตุฉ ุฃู†ุช ุจุชุนุฑูู‡ุง (ุฒูŠ ุชุฌู…ูŠุน string ุฃูˆ ุนู…ู„ูŠุฉ ุญุณุงุจูŠุฉ ู…ุนู‚ุฏุฉ).
MaxBy()(.NET 6+) ุจูŠุฑุฌุน ุงู„ุนู†ุตุฑ ู†ูุณู‡ ุงู„ู„ูŠ ู„ูŠู‡ ุฃุนู„ู‰ ู‚ูŠู…ุฉ ู„ู€ property ู…ุนูŠู†ุฉ.
MinBy()(.NET 6+) ุจูŠุฑุฌุน ุงู„ุนู†ุตุฑ ู†ูุณู‡ ุงู„ู„ูŠ ู„ูŠู‡ ุฃู‚ู„ ู‚ูŠู…ุฉ ู„ู€ property ู…ุนูŠู†ุฉ.
Any()(Boolean) ุจูŠุฑุฌุน true ู„ูˆ ููŠู‡ ุนู†ุตุฑ ูˆุงุญุฏ ุนู„ู‰ ุงู„ุฃู‚ู„ ุจูŠุญู‚ู‚ ุดุฑุท ู…ุนูŠู† (ุฃูˆ ู„ูˆ ู…ุด ูุงุถูŠุฉ).
All()(Boolean) ุจูŠุฑุฌุน true ู„ูˆ ูƒู„ ุงู„ุนู†ุงุตุฑ ุจุชุญู‚ู‚ ุดุฑุท ู…ุนูŠู†.

ุฃู…ุซู„ุฉ:

Console.WriteLine("\n--- Aggregate Operators ---");
 
// Sum (Needs a numeric property)
var totalSalary = employees.Sum(e => e.Salary);
Console.WriteLine($"Total Salary: {totalSalary}");
 
// Min (Needs a comparable property)
var minSalary = employees.Min(e => e.Salary);
Console.WriteLine($"Minimum Salary: {minSalary}");
 
// Max
var maxSalary = employees.Max(e => e.Salary);
Console.WriteLine($"Maximum Salary: {maxSalary}");
 
// Average
var averageSalary = employees.Average(e => e.Salary);
Console.WriteLine($"Average Salary: {averageSalary:F2}"); // F2 for formatting
 
// Count
var employeeCount = employees.Count(); // Total number of employees
Console.WriteLine($"Total Employees: {employeeCount}");
var maleCount = employees.Count(e => e.Gender == "Male"); // Number of male employees
Console.WriteLine($"Male Employees: {maleCount}");
 
// Any (Checks for existence)
bool hasHighEarner = employees.Any(e => e.Salary > 7000); // Is there anyone earning > 7000?
Console.WriteLine($"Any employee earns > 7000? {hasHighEarner}");
bool listIsNotEmpty = employees.Any(); // Is the list not empty?
Console.WriteLine($"Is the list not empty? {listIsNotEmpty}");
 
// All (Checks if all elements satisfy a condition)
bool allEarnAbove3000 = employees.All(e => e.Salary > 3000); // Does everyone earn > 3000?
Console.WriteLine($"All employees earn > 3000? {allEarnAbove3000}");
 
// Aggregate (Example: Concatenate all names)
string allNames = employees
                    .Select(e => e.Name) // First select the names
                    .Aggregate((currentNames, nextName) => currentNames + ", " + nextName); // Aggregate them
Console.WriteLine($"All Names Concatenated: {allNames}");
// Aggregate Example: Calculate product of salaries (just for demo, not meaningful)
// Need to handle potential zero salary if calculating product
long salaryProduct = employees.Select(e => (long)e.Salary).Aggregate(1L, (acc, salary) => acc * (salary == 0 ? 1 : salary)); // Start with 1L (long)
Console.WriteLine($"Salary Product (Example): {salaryProduct}");
 
 
// MaxBy / MinBy (.NET 6+)
// Find the employee object with the highest salary
var highestEarner = employees.MaxBy(e => e.Salary);
Console.WriteLine($"Highest Earning Employee: {highestEarner?.Name} ({highestEarner?.Salary})");
// Find the employee object with the lowest salary
var lowestEarner = employees.MinBy(e => e.Salary);
Console.WriteLine($"Lowest Earning Employee: {lowestEarner?.Name} ({lowestEarner?.Salary})");
 

ู…ู„ุงุญุธุงุช ุนู„ู‰ Sum, Min, Max, Average:

  • ู„ูˆ ุงุณุชุฎุฏู…ุชู‡ู… ุนู„ู‰ sequence ู…ู† objects (ุฒูŠ employees) ู…ู† ุบูŠุฑ ู…ุง ุชุญุฏุฏ ุงู„ู€ property ุงู„ู„ูŠ ู‡ูŠุดุชุบู„ูˆุง ุนู„ูŠู‡ุง (ูŠุนู†ูŠ ุชู‚ูˆู„ employees.Sum() ุจุณ)ุŒ ุงู„ู€ class ุจุชุงุน ุงู„ู€ object ุฏู‡ (ุงู„ู„ูŠ ู‡ูˆ Employee) ู„ุงุฒู… ูŠูƒูˆู† ุจูŠุนู…ู„ implement ู„ู€ interface ุฒูŠ Cs ICompareable ุนุดุงู† ุงู„ู€ operator ูŠุนุฑู ูŠู‚ุงุฑู† ุฃูˆ ูŠุฌู…ุน ุนู„ู‰ ุฃุณุงุณ ุฅูŠู‡. ุจุณ ุงู„ุทุฑูŠู‚ุฉ ุฏูŠ ู…ุด ุนู…ู„ูŠุฉ ูˆู…ุด ุจู†ุณุชุฎุฏู…ู‡ุง ุบุงู„ุจู‹ุง.
  • ุงู„ุฃุญุณู† ุฏุงูŠู…ู‹ุง ุฅู†ูƒ ุชุญุฏุฏ ุงู„ู€ property ุงู„ู„ูŠ ุนุงูŠุฒ ุชุนู…ู„ ุนู„ูŠู‡ุง ุงู„ุนู…ู„ูŠุฉ ุจุงุณุชุฎุฏุงู… lambda expression (ุฒูŠ employees.Sum(e => e.Salary)).
  • ู„ูŠู‡ู… overloads ูƒุชูŠุฑ ุนุดุงู† ูŠุชุนุงู…ู„ูˆุง ู…ุน ุฃู†ูˆุงุน ุฃุฑู‚ุงู… ู…ุฎุชู„ูุฉ (int, double, decimal, long,Nullable versions, etc.).

ู…ู‚ุงุฑู†ุฉ Max/Min ุจู€ MaxBy/MinBy:

  • ุงู„ู€ Max(e => e.Salary): ุจุชุฑุฌุน ุฃุนู„ู‰ ู‚ูŠู…ุฉ ู„ู„ู…ุฑุชุจ ู†ูุณู‡ุง (ู…ุซู„ู‹ุง 8000).
  • ุงู„ู€ MaxBy(e => e.Salary): ุจุชุฑุฌุน ุงู„ู…ูˆุธู ู†ูุณู‡ (Employee object) ุงู„ู„ูŠ ุนู†ุฏู‡ ุฃุนู„ู‰ ู…ุฑุชุจ.
  • ุงู„ู€ MaxBy/MinBy ู…ููŠุฏูŠู† ู„ู…ุง ุชูƒูˆู† ุนุงูŠุฒ ุงู„ู€ object ูƒู„ู‡ ู…ุด ุจุณ ุงู„ู‚ูŠู…ุฉ. (ู…ุชุงุญูŠู† ู…ู† .NET 6).
  • ู‚ุจู„ .NET 6ุŒ ูƒู†ุง ุจู†ุนู…ู„ ู†ูุณ ูˆุธูŠูุฉ MaxBy ุนู† ุทุฑูŠู‚ OrderByDescending(...).First().
  • ู…ู‡ู… ู„ู€ EF Core: MaxBy/MinBy ู…ู…ูƒู† ูŠูƒูˆู†ูˆุง ู„ุณู‡ ู…ุด ู…ุชุฑุฌู…ูŠู† ูƒูˆูŠุณ ู„ู€ SQL ููŠ ูƒู„ ุฅุตุฏุงุฑุงุช EF CoreุŒ ู„ูƒู† ุงู„ุฏุนู… ุจูŠุชุญุณู†.

ู…ู‚ุงุฑู†ุฉ Count (ุงู„ู€ LINQ Operator) ุจู€ Count (ุงู„ู€ Property):

  • ุงู„ู€ List<T>.Count (Property): ุฏูŠ property ู…ูˆุฌูˆุฏุฉ ููŠ List ูˆ Array ูˆุจุนุถ ุงู„ู€ collections ุงู„ุชุงู†ูŠุฉ. ุจุชุฑุฌุน ุนุฏุฏ ุงู„ุนู†ุงุตุฑ ุจุณุฑุนุฉ ุฌุฏู‹ุง ู„ุฅู† ุงู„ุนุฏุฏ ุจูŠูƒูˆู† ู…ุชุฎุฒู†. ู…ุง ูŠู†ูุนุด ุชุณุชุฎุฏู…ู‡ุง ู…ุน IEnumerable ุนุงู…ุฉู‹ (ู„ุฅู† IEnumerable ู…ุด ุจูŠุถู…ู† ุฅู† ุงู„ุนุฏุฏ ู…ุนุฑูˆู ู…ุณุจู‚ู‹ุง).
  • ุงู„ู€ .Count() (LINQ Operator/Extension Method): ุฏูŠ method ุจุชุดุชุบู„ ู…ุน ุฃูŠ IEnumerable.
    • ู„ูˆ ุงู„ู€ IEnumerable ุฏู‡ ุฃุตู„ู‹ุง List ุฃูˆ ArrayุŒ ุงู„ู€ method ุฏูŠ ุจุชูƒูˆู† ุฐูƒูŠุฉ ูƒูุงูŠุฉ ุฅู†ู‡ุง ุชุณุชุฎุฏู… ุงู„ู€ Count/Length property ุนุดุงู† ุชุฌูŠุจ ุงู„ุนุฏุฏ ุจุณุฑุนุฉ.
    • ู„ูˆ ุงู„ู€ IEnumerable ุฏู‡ ู†ูˆุน ุชุงู†ูŠ (ุฒูŠ ู†ุชูŠุฌุฉ query ู„ุณู‡ ู…ู†ูุฐุชุด)ุŒ ุงู„ู€ method ุฏูŠ ุจุชุถุทุฑ ุชู„ู ุนู„ู‰ ูƒู„ ุงู„ุนู†ุงุตุฑ ุนุดุงู† ุชุนุฏู‡ู… (ูˆุฏู‡ ู…ู…ูƒู† ูŠูƒูˆู† ุฃุจุทุฃ ู„ูˆ ุงู„ู€ sequence ูƒุจูŠุฑุฉ).
    • ุงู„ู€ Operator ู„ูŠู‡ overload ุจูŠุงุฎุฏ predicate ุนุดุงู† ูŠุนุฏ ุงู„ุนู†ุงุตุฑ ุงู„ู„ูŠ ุจุชุญู‚ู‚ ุดุฑุท ู…ุนูŠู† (employees.Count(e => e.Gender == "Male")). ุงู„ู€ Property ุทุจุนู‹ุง ู…ุง ูŠู†ูุนุด ุชุนู…ู„ ูƒุฏู‡.

ุฅู…ุชู‰ ุฃุณุชุฎุฏู… Any() ุจุฏู„ Count() > 0ุŸ

  • ู„ูˆ ูƒู„ ุงู„ู„ูŠ ูŠู‡ู…ูƒ ุชุนุฑูู‡ ู‡ูˆ โ€œู‡ู„ ููŠู‡ ุฃูŠ ุนู†ุตุฑ ุจูŠุญู‚ู‚ ุงู„ุดุฑุท ุฏู‡ุŸโ€ ุฃูˆ โ€œู‡ู„ ุงู„ู„ูŠุณุชุฉ ุฏูŠ ู…ุด ูุงุถูŠุฉุŸโ€ุŒ ุฏุงูŠู…ู‹ุง ุงุณุชุฎุฏู… Any().
  • ุงู„ู€ Any() ุฃุณุฑุน ุจูƒุชูŠุฑ ู…ู† Count() > 0 ููŠ ู…ุนุธู… ุงู„ุญุงู„ุงุช (ุฎุตูˆุตู‹ุง ู…ุน databases ุฃูˆ sequences ู…ุด List/Array).
  • ู„ูŠู‡ุŸ ู„ุฅู† Any() ุจุชู‚ู ุฃูˆู„ ู…ุง ุชู„ุงู‚ูŠ ุฃูˆู„ ุนู†ุตุฑ ุจูŠุญู‚ู‚ ุงู„ุดุฑุท (ุฃูˆ ุฃูˆู„ ุนู†ุตุฑ ู„ูˆ ู…ููŠุด ุดุฑุท).
  • ุงู„ู€ Count() (ู„ูˆ ู…ุด List/Array) ุจุชุถุทุฑ ุชู„ู ุนู„ู‰ ูƒู„ ุงู„ุนู†ุงุตุฑ ุนุดุงู† ุชุฌูŠุจ ุงู„ุนุฏุฏ ุงู„ูƒู„ูŠุŒ ูˆุจุนุฏูŠู† ุชู‚ุงุฑู†ู‡ ุจุงู„ุตูุฑ.
  • ู…ุชุณุชุฎุฏู…ุด Count() ุบูŠุฑ ู„ูˆ ุฃู†ุช ูุนู„ู‹ุง ู…ุญุชุงุฌ ุงู„ุนุฏุฏ ู†ูุณู‡ ู„ุณุจุจ ู…ุง.
  • ุงุชูƒู„ู…ู†ุง ุนู† Cs Aggregate ุจุงู„ุชูุตูŠู„ ู‡ู†ุง

5. Casting / Conversion Operators (ุชุญูˆูŠู„ ุงู„ู†ูˆุน)

ุงู„ู€ Operators ุฏูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ุนุดุงู† ู†ุญูˆู„ ู†ุชูŠุฌุฉ LINQ query (ุงู„ู„ูŠ ุบุงู„ุจู‹ุง ุจุชูƒูˆู† IEnumerable) ู„ู†ูˆุน collection ู…ุนูŠู† ูˆู…ุดู‡ูˆุฑ ุฒูŠ List ุฃูˆ Array ุฃูˆ Dictionary. (ุฏูˆู„ Immediate Execution).

ToList()

  • ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู€ List<T>. ุฏูŠ ุฃูƒุชุฑ ูˆุงุญุฏุฉ ุจู†ุณุชุฎุฏู…ู‡ุง ุบุงู„ุจู‹ุง ุนุดุงู† ู†ุฌุจุฑ ุงู„ู€ query ุฅู†ู‡ ูŠุชู†ูุฐ ูˆู†ุงุฎุฏ ุงู„ู†ุชุงุฆุฌ ููŠ List.
IEnumerable<Employee> query = employees.Where(e => e.Salary > 5000); // Deferred
List<Employee> highEarnersList = query.ToList(); // Immediate Execution
 
Console.WriteLine("\nHigh Earners List (ToList):");
highEarnersList.ForEach(e => Console.WriteLine(e.Name)); // Can use List methods now

ToArray()

  • ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู€ Array (T[]).
Employee[] highEarnersArray = employees.Where(e => e.Salary > 5000).ToArray(); // Immediate
 
Console.WriteLine("\nHigh Earners Array (ToArray):");
foreach(var emp in highEarnersArray) { Console.WriteLine(emp.Name); }

ToDictionary()

  • ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู€ Dictionary<TKey, TValue>.
  • ุจุชุญุชุงุฌ ุชุญุฏุฏ ู„ู‡ุง ุญุงุฌุชูŠู† ุจู€ lambda expressions:
    1. ุงู„ู€ keySelector: ุงุฒุงูŠ ุชุฌูŠุจ ุงู„ู€ Key ุจุชุงุน ุงู„ู€ Dictionary ู…ู† ูƒู„ ุนู†ุตุฑ ููŠ ุงู„ู€ sequence. ุงู„ู€ Key ู„ุงุฒู… ูŠูƒูˆู† unique.
    2. ุงู„ู€ elementSelector (ุงุฎุชูŠุงุฑูŠ): ุงุฒุงูŠ ุชุฌูŠุจ ุงู„ู€ Value ุจุชุงุน ุงู„ู€ Dictionary. ู„ูˆ ู…ุญุฏุฏุชูˆุดุŒ ุงู„ู€ Value ู‡ูŠูƒูˆู† ุงู„ุนู†ุตุฑ ู†ูุณู‡.
try
{
    // Create a dictionary where Key is Employee Id, Value is Employee Name
    Dictionary<int, string> employeeNameDict = employees
        .ToDictionary(
            emp => emp.Id,        // Key selector: Use employee Id as the key
            emp => emp.Name       // Element selector: Use employee Name as the value
        );

    Console.WriteLine("\nEmployee Dictionary (Id -> Name):");
    foreach (var kvp in employeeNameDict)
    {
        Console.WriteLine("Key: {kvp.Key}, Value: {kvp.Value}");
    }

    // Example where Value is the employee object itself
    Dictionary<int, Employee> employeeDict = employees.ToDictionary(emp => emp.Id); // Element selector omitted
    Console.WriteLine($"\nEmployee with Id 2 from Dictionary: {employeeDict[2].Name}");

    // This will throw an exception if keys are not unique
    // Dictionary<string, Employee> dictByGender = employees.ToDictionary(emp => emp.Gender); // Throws Exception
}
catch (Exception ex) 
{ 
	Console.WriteLine($"ToDictionary() Exception: {ex.Message}");
}

ToHashSet()

  • ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู€ HashSet<T>.
  • ุงู„ู€ HashSet ุจูŠุถู…ู† ุฅู† ุงู„ุนู†ุงุตุฑ ุชูƒูˆู† unique (ู…ููŠู‡ูˆุด ุชูƒุฑุงุฑ).
  • ู…ุชุงุญ ู…ู† .NET 6+.
// Example: Get a set of unique genders
HashSet<string> genders = employees.Select(e => e.Gender).ToHashSet();
 
Console.WriteLine("\nUnique Genders (ToHashSet):");
Console.WriteLine(string.Join(", ", genders)); // Output: Male, Female (order not guaranteed)

ToLookup()

  • ุจุชุญูˆู„ ุงู„ู€ sequence ู„ู€ ILookup<TKey, TElement>.
  • ุงู„ู€ Lookup ุดุจู‡ ุงู„ู€ DictionaryุŒ ุจุณ ุจูŠุณู…ุญ ุจูˆุฌูˆุฏ ุฃูƒุชุฑ ู…ู† ุนู†ุตุฑ ู„ู†ูุณ ุงู„ู€ Key. ุงู„ู€ Value ุจูŠูƒูˆู† ุนุจุงุฑุฉ ุนู† IEnumerable ุจุงู„ุนู†ุงุตุฑ ุงู„ู„ูŠ ู„ูŠู‡ุง ู†ูุณ ุงู„ู€ Key.
  • ู…ููŠุฏ ุฌุฏู‹ุง ู„ูˆ ุนุงูŠุฒ ุชุนู…ู„ grouping ู„ู„ุฏุงุชุง ุจุณ ููŠ ุดูƒู„ ุชู‚ุฏุฑ ุชูˆุตู„ ู„ู‡ ุจุงู„ู€ key ุจุณุฑุนุฉ.
// Create a Lookup grouping employees by Gender
ILookup<string, Employee> employeesByGender = employees.ToLookup(emp => emp.Gender);
 
Console.WriteLine("\nEmployees Lookup by Gender (ToLookup):");
 
// Access employees for a specific key ("Male")
Console.WriteLine("Male Employees:");
if (employeesByGender.Contains("Male")) // Good practice to check if key exists
{
    foreach (var emp in employeesByGender["Male"]) // Access the IEnumerable<Employee> for the key
    {
        Console.WriteLine($"- {emp.Name}");
    }
}
 
// Access employees for another key ("Female")
Console.WriteLine("Female Employees:");
foreach (var emp in employeesByGender["Female"])
{
    Console.WriteLine($"- {emp.Name}");
}
 
// Access a non-existent key (doesn't throw exception, returns empty sequence)
Console.WriteLine("Employees with Gender 'Other':");
foreach (var emp in employeesByGender["Other"]) // This loop won't execute
{
    Console.WriteLine($"- {emp.Name}");
}

6. Generation Operators (ุฅู†ุดุงุก Sequences)

ุงู„ู€ Operators ุฏูŠ ู…ุฎุชู„ูุฉ ุนู† ุงู„ู„ูŠ ูุงุชูˆุงุŒ ู„ุฅู†ู‡ุง ู…ุด ุจุชุดุชุบู„ ุนู„ู‰ input sequence ู…ูˆุฌูˆุฏุฉุŒ ู‡ูŠ ู†ูุณู‡ุง ุจุชู†ุดุฆ (generate) sequence ุฌุฏูŠุฏุฉ. (ุฏูˆู„ Deferred ExecutionุŒ ุจุณ ุจูŠู†ุดุฆูˆุง sequence ุชู‚ุฏุฑ ุชุนู…ู„ ุนู„ูŠู‡ุง loop).

ู„ุงุฒู… ู†ู†ุงุฏูŠู‡ู… ูƒู€ Static Methods ู…ู† ุงู„ู€ Enumerable class.

Enumerable.Range(start, count)

  • ุจุชู†ุดุฆ sequence ู…ู† ุงู„ุฃุฑู‚ุงู… ุงู„ุตุญูŠุญุฉ ุงู„ู…ุชุณู„ุณู„ุฉ.
  • ุงู„ู€ start: ุงู„ุฑู‚ู… ุงู„ู„ูŠ ู‡ุชุจุฏุฃ ุจูŠู‡.
  • ุงู„ู€ count: ุนุฏุฏ ุงู„ุฃุฑู‚ุงู… ุงู„ู„ูŠ ุนุงูŠุฒ ุชู†ุดุฆู‡ุง.
// Generate numbers from 5 to 9 (start=5, count=5)
IEnumerable<int> numberRange = Enumerable.Range(5, 5); // 5, 6, 7, 8, 9
 
Console.WriteLine("\nGenerated Range (Range):");
Console.WriteLine(string.Join(", ", numberRange));

Enumerable.Repeat(element, count)

  • ุจุชู†ุดุฆ sequence ุนู† ุทุฑูŠู‚ ุชูƒุฑุงุฑ ู‚ูŠู…ุฉ ู…ุนูŠู†ุฉ ุนุฏุฏ ู…ุนูŠู† ู…ู† ุงู„ู…ุฑุงุช.
  • ุงู„ู€ element: ุงู„ู‚ูŠู…ุฉ ุงู„ู„ูŠ ุนุงูŠุฒ ุชูƒุฑุฑู‡ุง.
  • ุงู„ู€ count: ุนุฏุฏ ู…ุฑุงุช ุงู„ุชูƒุฑุงุฑ.
// Repeat the string "Hi" 4 times
IEnumerable<string> repeatedHi = Enumerable.Repeat("Hi", 4); // "Hi", "Hi", "Hi", "Hi"
 
Console.WriteLine("\nGenerated Repetition (Repeat):");
Console.WriteLine(string.Join(", ", repeatedHi));
 
// Repeat the number 0 five times
var zeros = Enumerable.Repeat(0, 5); // 0, 0, 0, 0, 0
Console.WriteLine(string.Join(", ", zeros));
 

Enumerable.Empty<T>()

  • ุจุชู†ุดุฆ sequence ูุงุถูŠุฉ ู…ู† ู†ูˆุน ู…ุนูŠู† T.
  • ู…ููŠุฏุฉ ุฃุญูŠุงู†ู‹ุง ู„ูˆ ุนุงูŠุฒ ุชุฑุฌุน sequence ูุงุถูŠุฉ ู…ู† method ุจุฏู„ ู…ุง ุชุฑุฌุน null.
// Create an empty sequence of Products
IEnumerable<Product> emptyProducts = Enumerable.Empty<Product>();
 
Console.WriteLine($"\nIs emptyProducts sequence empty? {!emptyProducts.Any()}"); // True

7. Set Operators (ุนู…ู„ูŠุงุช ุงู„ู…ุฌู…ูˆุนุงุช)

ุงู„ู€ Operators ุฏูŠ ุจุชุชุนุงู…ู„ ู…ุน ุงู„ู€ sequences ูƒุฃู†ู‡ุง sets (ู…ุฌู…ูˆุนุงุช)ุŒ ูˆุจุชุณู…ุญ ู„ูƒ ุชุนู…ู„ ุนู…ู„ูŠุงุช ุฒูŠ ุงู„ุงุชุญุงุฏ ูˆุงู„ุชู‚ุงุทุน ูˆุงู„ูุฑู‚ ุจูŠู† ู…ุฌู…ูˆุนุชูŠู†ุŒ ุฃูˆ ุชุดูŠู„ ุงู„ุชูƒุฑุงุฑ ู…ู† ู…ุฌู…ูˆุนุฉ ูˆุงุญุฏุฉ. (ุฏูˆู„ Deferred Execution).

ู†ู‚ุทุฉ ู…ู‡ู…ุฉ: ู…ู‚ุงุฑู†ุฉ ุงู„ุนู†ุงุตุฑ (Overriding Equals & GetHashCode)

  • ู„ู…ุง ุงู„ู€ Set Operators ุฏูŠ ุจุชู‚ุงุฑู† ุจูŠู† ุนู†ุตุฑูŠู† ุนุดุงู† ุชุนุฑู ู‡ู„ ู‡ู…ุง ู…ุชุณุงูˆูŠูŠู† (ุนุดุงู† ู…ุซู„ู‹ุง ุชุดูŠู„ ุงู„ุชูƒุฑุงุฑ ููŠ Distinct ุฃูˆ Union)ุŒ ู‡ูŠ ุจุชุณุชุฎุฏู… ุทุฑูŠู‚ุฉ ุงู„ู…ู‚ุงุฑู†ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ.
  • ู„ูˆ ุงู„ุนู†ุงุตุฑ ุฏูŠ primitive types (ุฒูŠ int, string, bool)ุŒ ุงู„ู…ู‚ุงุฑู†ุฉ ุจุชูƒูˆู† ุนู„ู‰ ุงู„ู‚ูŠู…ุฉ ู†ูุณู‡ุงุŒ ูˆุฏู‡ ุบุงู„ุจู‹ุง ุงู„ู„ูŠ ุฅุญู†ุง ุนุงูŠุฒูŠู†ู‡.
  • ู„ูƒู† ู„ูˆ ุงู„ุนู†ุงุตุฑ ุฏูŠ objects ู…ู† class ุฅุญู†ุง ุนุงู…ู„ูŠู†ู‡ (ุฒูŠ Employee ุฃูˆ Product)ุŒ ุงู„ู…ู‚ุงุฑู†ุฉ ุงู„ุงูุชุฑุงุถูŠุฉ ุจุชูƒูˆู† ุจู…ู‚ุงุฑู†ุฉ ุงู„ู€ Reference (ุนู†ูˆุงู† ุงู„ู€ object ููŠ ุงู„ุฐุงูƒุฑุฉ)ุŒ ู…ุด ุจู…ู‚ุงุฑู†ุฉ ู‚ูŠู… ุงู„ู€ properties ุงู„ู„ูŠ ุฌูˆุงู‡. ุฏู‡ ู…ุนู†ุงู‡ ุฅู† ุงุชู†ูŠู† Employee objects ู„ูŠู‡ู… ู†ูุณ ุงู„ู€ Id ูˆุงู„ู€ Name ู‡ูŠุนุชุจุฑูˆุง ู…ุฎุชู„ููŠู† ู„ูˆ ู‡ู…ุง instances ู…ู†ูุตู„ุฉ.
  • ุงู„ุญู„: ู„ูˆ ุนุงูŠุฒ ุงู„ู€ Set Operators ุชู‚ุงุฑู† ุงู„ู€ objects ุจุชุงุนุชูƒ ุจู†ุงุกู‹ ุนู„ู‰ ู‚ูŠู… ุงู„ู€ propertiesุŒ ู„ุงุฒู… ุชุนู…ู„ override ู„ุงุชู†ูŠู† methods ู…ู‡ู…ูŠู† ุฌูˆู‡ ุงู„ู€ class ุจุชุงุนูƒ (ุงู„ู„ูŠ ูˆุฑุซุชู‡ู… ู…ู† System.Object ูˆูƒู†ุง ุงุชูƒู„ู…ู†ุง ุนู†ู‡ุง ููŠ Cs Equality):
    1. ุงู„ู€ Equals(object obj): ุชุนุฑู ููŠู‡ุง ุฅู…ุชู‰ ุชุนุชุจุฑ ุงุชู†ูŠู† objects ู…ู† ุงู„ู€ class ุฏู‡ ู…ุชุณุงูˆูŠูŠู† (ู…ุซู„ู‹ุง ู„ูˆ ู„ูŠู‡ู… ู†ูุณ ุงู„ู€ Id).
    2. ุงู„ู€ GetHashCode(): ู„ุงุฒู… ูƒู…ุงู† ุชุนู…ู„ู‡ุง override ุจุญูŠุซ ุฅู† ุฃูŠ ุงุชู†ูŠู† objects ู…ุชุณุงูˆูŠูŠู† ุญุณุจ EqualsุŒ ู„ุงุฒู… ูŠูƒูˆู† ู„ูŠู‡ู… ู†ูุณ ุงู„ู€ HashCode. ู„ูˆ ู…ุนู…ู„ุชุด override ู„ู€ GetHashCode ุตุญุŒ ุงู„ู€ Set Operators (ูˆูƒู…ุงู† Dictionary ูˆ HashSet) ู…ู…ูƒู† ุชุดุชุบู„ ุบู„ุท.
      • ู„ูŠู‡ ุจู†ุนู…ู„ override ู„ู„ุงุชู†ูŠู† ู…ุน ุจุนุถุŸ ู„ุฅู† ุงู„ู€ Set Operators ูˆุงู„ู€ Collections ุงู„ู„ูŠ ุจุชุนุชู…ุฏ ุนู„ู‰ hash (ุฒูŠ HashSet, Dictionary) ุจุชุณุชุฎุฏู… GetHashCode ุงู„ุฃูˆู„ ูƒุทุฑูŠู‚ุฉ ุณุฑูŠุนุฉ ุนุดุงู† ุชู‚ุณู… ุงู„ุนู†ุงุตุฑ ู„ู…ุฌู…ูˆุนุงุช ุตุบูŠุฑุฉ (buckets)ุŒ ูˆุจุนุฏูŠู† ุฌูˆู‡ ุงู„ู€ bucket ุงู„ูˆุงุญุฏ ุจุณ ุจุชู‚ุงุฑู† ุจุงุณุชุฎุฏุงู… Equals. ู„ูˆ ุงุชู†ูŠู† objects ู…ุชุณุงูˆูŠูŠู† ุจุณ ุงู„ู€ HashCode ุจุชุงุนู‡ู… ู…ุฎุชู„ูุŒ ู…ู…ูƒู† ูŠุชุญุทูˆุง ููŠ buckets ู…ุฎุชู„ูุฉ ูˆู…ูŠุชู‚ุงุฑู†ูˆุด ุจู€ Equals ุฃุตู„ู‹ุง.
      • ุฅุฒุงูŠ ู†ุนู…ู„ override ู„ู€ GetHashCodeุŸ ุงู„ุทุฑูŠู‚ุฉ ุงู„ุดุงุฆุนุฉ ุฅู†ูƒ ุชุฎุชุงุฑ ุงู„ู€ properties ุงู„ุฃุณุงุณูŠุฉ ุงู„ู„ูŠ ุจุชุนุฑู ุงู„ู€ equality (ุฒูŠ ุงู„ู€ Id) ูˆุชุฏู…ุฌ ุงู„ู€ HashCodes ุจุชุงุนุชู‡ู… ู…ุน ุจุนุถ ุจุงุณุชุฎุฏุงู… ุนู…ู„ูŠุฉ ุฒูŠ XOR (^) ุฃูˆ ุจุงุณุชุฎุฏุงู… HashCode.Combine() (ููŠ .NET ุงู„ุฃุญุฏุซ).
// Example inside Product class (assuming equality is based on Id only)
public class Product // : IEquatable<Product> // Optional: Implement IEquatable for better performance
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public double Price { get; set; }
    public override string ToString() => $"Id: {Id}, Name: {Name}, Category: {Category}, Price: {Price}";

    // --- Overriding Equals and GetHashCode ---
    public override bool Equals(object obj)
    {
        // Basic implementation comparing by Id
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        Product other = (Product)obj;
        return Id == other.Id;

        // OR use pattern matching (C# 7+)
        // return obj is Product other && this.Id == other.Id;
    }

    // Must override GetHashCode if Equals is overridden
    public override int GetHashCode()
    {
        // Basic implementation using Id's hash code
        // If using multiple properties for Equals, combine their hash codes
        // return HashCode.Combine(Id, Name, Category); // Example for multiple properties (.NET Core+)
        return Id.GetHashCode();
    }
    // --- End Overrides ---

    // Optional: Implement IEquatable<T>
    // public bool Equals(Product other)
    // {
    //     if (other == null) return false;
    //     return this.Id == other.Id;
    // }
}
  • ุจุนุฏ ู…ุง ุชุนู…ู„ override ุตุญุŒ ุงู„ู€ Set Operators ู‡ุชุดุชุบู„ ุฒูŠ ู…ุง ุฅู†ุช ู…ุชูˆู‚ุน ุนู„ู‰ ุงู„ู€ objects ุจุชุงุนุชูƒ.
  • ุจุฏูŠู„: ู„ูˆ ู…ุด ุนุงูŠุฒ ุชุนู…ู„ override ููŠ ุงู„ู€ class ู†ูุณู‡ุŒ ู…ุนุธู… ุงู„ู€ Set Operators ู„ูŠู‡ุง overload ุชุงู†ูŠ ุจูŠุงุฎุฏ parameter ู…ู† ู†ูˆุน IEqualityComparer<T>. ุฏู‡ interface ุจุชุนู…ู„ ู„ู‡ implement ููŠ class ู…ู†ูุตู„ุŒ ูˆุจุชุนุฑู ููŠู‡ ุงู„ู€ Equals ูˆุงู„ู€ GetHashCode ุงู„ู„ูŠ ุฅู†ุช ุนุงูŠุฒ ุชุณุชุฎุฏู…ู‡ู… ู„ู„ู…ู‚ุงุฑู†ุฉ ุฏูŠ ุจุณ.

Distinct()

  • ุจุชุดูŠู„ ุงู„ุนู†ุงุตุฑ ุงู„ู…ูƒุฑุฑุฉ ู…ู† sequence ูˆุงุญุฏุฉ. ุจุชุฑุฌุน sequence ููŠู‡ุง ุงู„ุนู†ุงุตุฑ ุงู„ู€ unique ุจุณ.
List<int> numbersWithDuplicates = new List<int> { 1, 2, 2, 3, 1, 4, 5, 4 };
var distinctNumbers = numbersWithDuplicates.Distinct(); // 1, 2, 3, 4, 5
 
Console.WriteLine("\nDistinct Numbers:");
Console.WriteLine(string.Join(", ", distinctNumbers));
 
// Example with Products (Needs Equals/GetHashCode override based on Id)
List<Product> productListDups = new List<Product>
{
    new Product { Id = 101, Name = "Laptop", Category = "Devices", Price = 25000 },
    new Product { Id = 102, Name = "Keyboard", Category = "Devices", Price = 1500 },
    new Product { Id = 101, Name = "Laptop New", Category = "Devices", Price = 26000 }, // Duplicate Id
};
var distinctProducts = productListDups.Distinct(); // Will keep only one product with Id 101
Console.WriteLine("\nDistinct Products (by Id):");
foreach(var p in distinctProducts) { Console.WriteLine(p); }

Union()

  • ุจุชุฌูŠุจ ุงุชุญุงุฏ ู…ุฌู…ูˆุนุชูŠู† (sequence 1 + sequence 2)ุŒ ู…ุน ุฅุฒุงู„ุฉ ุงู„ุนู†ุงุตุฑ ุงู„ู…ูƒุฑุฑุฉ ุจูŠู† ุงู„ู…ุฌู…ูˆุนุชูŠู† ุฃูˆ ุฌูˆู‡ ูƒู„ ู…ุฌู…ูˆุนุฉ.
List<int> listA = new List<int> { 1, 2, 3, 4 };
List<int> listB = new List<int> { 3, 4, 5, 6 };
var unionResult = listA.Union(listB); // 1, 2, 3, 4, 5, 6
 
Console.WriteLine("\nUnion of listA and listB:");
Console.WriteLine(string.Join(", ", unionResult));

Concat()

  • ุจุชุฏู…ุฌ (Concatenate) ู…ุฌู…ูˆุนุชูŠู† ูˆุฑุง ุจุนุถ ู…ู† ุบูŠุฑ ู…ุง ุชุดูŠู„ ุฃูŠ ุชูƒุฑุงุฑ. ุจุชุฑุฌุน ูƒู„ ุนู†ุงุตุฑ ุงู„ุฃูˆู„ู‰ ูˆุจุนุฏู‡ุง ูƒู„ ุนู†ุงุตุฑ ุงู„ุชุงู†ูŠุฉ.
  • ุฏูŠ ุฒูŠ UNION ALL ููŠ SQL.
var concatResult = listA.Concat(listB); // 1, 2, 3, 4, 3, 4, 5, 6
 
Console.WriteLine("\nConcatenation of listA and listB:");
Console.WriteLine(string.Join(", ", concatResult));
 
// Note: listA.Union(listB) is equivalent to listA.Concat(listB).Distinct()

Intersect()

  • ุจุชุฌูŠุจ ุชู‚ุงุทุน ู…ุฌู…ูˆุนุชูŠู†ุŒ ูŠุนู†ูŠ ุงู„ุนู†ุงุตุฑ ุงู„ู…ุดุชุฑูƒุฉ ุงู„ู…ูˆุฌูˆุฏุฉ ููŠ ุงู„ู…ุฌู…ูˆุนุชูŠู† ุงู„ุงุชู†ูŠู†.
var intersectResult = listA.Intersect(listB); // 3, 4
 
Console.WriteLine("\nIntersection of listA and listB:");
Console.WriteLine(string.Join(", ", intersectResult));

Except()

  • ุจุชุฌูŠุจ ุงู„ูุฑู‚ ุจูŠู† ู…ุฌู…ูˆุนุชูŠู†. ุจุชุฑุฌุน ุงู„ุนู†ุงุตุฑ ุงู„ู…ูˆุฌูˆุฏุฉ ููŠ ุงู„ู…ุฌู…ูˆุนุฉ ุงู„ุฃูˆู„ู‰ ูˆู…ุด ู…ูˆุฌูˆุฏุฉ ููŠ ุงู„ู…ุฌู…ูˆุนุฉ ุงู„ุชุงู†ูŠุฉ.
var exceptResult = listA.Except(listB); // 1, 2 (Elements in A that are not in B)
Console.WriteLine("\nElements in listA Except those in listB:");
Console.WriteLine(string.Join(", ", exceptResult));
 
var exceptResultReverse = listB.Except(listA); // 5, 6 (Elements in B that are not in A)
Console.WriteLine("\nElements in listB Except those in listA:");
Console.WriteLine(string.Join(", ", exceptResultReverse));

ุงู„ู€ ...By Operators (.NET 6+)

ุฒูŠ ู…ุง ููŠู‡ MaxBy/MinByุŒ ููŠู‡ ูƒู…ุงู† overloads ุฌุฏูŠุฏุฉ ู„ู„ู€ Set Operators ุฏูŠ ู…ู† ุฃูˆู„ .NET 6 ุจุชู†ุชู‡ูŠ ุจู€ By (ุฒูŠ DistinctBy, UnionBy, IntersectBy, ExceptBy).

  • ูุงูŠุฏุชู‡ู…: ุจูŠุฎู„ู‘ูˆูƒ ุชุญุฏุฏ key selector (ูŠุนู†ูŠ lambda expression ุจุชุฎุชุงุฑ property ู…ุนูŠู†ุฉ) ุนุดุงู† ุงู„ู…ู‚ุงุฑู†ุฉ ุชุชู… ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ู€ key ุฏู‡ ุจุณุŒ ุจุฏู„ ู…ุง ุชุญุชุงุฌ ุชุนู…ู„ override ู„ู€ Equals/GetHashCode ุฃูˆ ุชุณุชุฎุฏู… IEqualityComparer.

ู…ุซุงู„: ู†ุฌูŠุจ ุงู„ู…ู†ุชุฌุงุช ุงู„ู€ unique ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ู€ Category ุจุณ:

// Using DistinctBy ( .NET 6+) to get one product per category
var distinctByCategory = products.DistinctBy(p => p.Category);
 
Console.WriteLine("\nDistinct Products by Category (DistinctBy):");
foreach (var p in distinctByCategory)
{
    Console.WriteLine(p); // Gets Laptop (Devices), T-Shirt (Clothing) - or others depending on which comes first
}
 
// Example: Union products based on Category key
List<Product> moreProducts = new List<Product> {
    new Product { Id = 201, Name = "Jeans", Category = "Clothing", Price = 1200 },
    new Product { Id = 202, Name = "Monitor", Category = "Devices", Price = 5000 }
};
var unionByCategory = products.UnionBy(moreProducts, p => p.Category);
Console.WriteLine("\nUnion By Category:");
foreach (var p in unionByCategory) { Console.WriteLine(p); } // Shows one product per unique category from both lists

ุงู„ู€ ...By operators ุฏูŠ ุจุชุจุณุท ุงู„ุฏู†ูŠุง ุฌุฏู‹ุง ู„ู…ุง ุชูƒูˆู† ุนุงูŠุฒ ุชุนู…ู„ ู…ู‚ุงุฑู†ุฉ ุจู†ุงุกู‹ ุนู„ู‰ property ูˆุงุญุฏุฉ ุฃูˆ ุฃูƒุชุฑ ู…ู† ุบูŠุฑ ู…ุง ุชุนุฏู„ ุงู„ู€ class ุงู„ุฃุตู„ูŠ.

8. Quantifier Operators (ุชุญุฏูŠุฏ ุงู„ูƒู…ูŠุฉ - Boolean)

ุงู„ู€ Operators ุฏูŠ ุจุชุดุชุบู„ ุนู„ู‰ ุงู„ู€ sequence ูƒู„ู‡ุง ุนุดุงู† ุชุฑุฌุน ู‚ูŠู…ุฉ boolean (true ุฃูˆ false) ุจุชุฌุงูˆุจ ุนู„ู‰ ุณุคุงู„ ุนู† ูƒู…ูŠุฉ ุงู„ุนู†ุงุตุฑ ุงู„ู„ูŠ ุจุชุญู‚ู‚ ุดุฑุท ู…ุนูŠู†. (ุฏูˆู„ ู„ูŠู‡ู… ุณู„ูˆูƒ Immediate Execution ููŠ ุงู„ุบุงู„ุจ ู„ุฅู†ู‡ู… ู„ุงุฒู… ูŠูˆุตู„ูˆุง ู„ู†ุชูŠุฌุฉ true/false).

Any()

  • ุจุชุฑุฌุน true ู„ูˆ ููŠู‡ ุนู†ุตุฑ ูˆุงุญุฏ ุนู„ู‰ ุงู„ุฃู‚ู„ ููŠ ุงู„ู€ sequence ุจูŠุญู‚ู‚ ุงู„ุดุฑุท ุงู„ู„ูŠ ู…ุฏูŠู‡ูˆู„ู‡ุง.
  • ู„ูˆ ู…ู† ุบูŠุฑ ุดุฑุท (Any())ุŒ ุจุชุฑุฌุน true ู„ูˆ ุงู„ู€ sequence ู…ุด ูุงุถูŠุฉ (ููŠู‡ุง ุนู†ุตุฑ ูˆุงุญุฏ ุนู„ู‰ ุงู„ุฃู‚ู„).
  • ุจุชู‚ู ุฃูˆู„ ู…ุง ุชู„ุงู‚ูŠ ุฃูˆู„ ุนู†ุตุฑ ูŠุญู‚ู‚ ุงู„ุดุฑุท (ุนุดุงู† ูƒุฏู‡ ุณุฑูŠุนุฉ).
bool anyMales = employees.Any(e => e.Gender == "Male"); // true
Console.WriteLine($"\nAny males? {anyMales}");
 
bool anySalaryOver9k = employees.Any(e => e.Salary > 9000); // false
Console.WriteLine($"Any salary > 9k? {anySalaryOver9k}");
 
bool isEmployeeListNotEmpty = employees.Any(); // true
Console.WriteLine($"Is employees list not empty? {isEmployeeListNotEmpty}");
 
List<int> emptyList = new List<int>();
bool isEmptyListNotEmpty = emptyList.Any(); // false
Console.WriteLine($"Is emptyList not empty? {isEmptyListNotEmpty}");

All()

  • ุจุชุฑุฌุน true ู„ูˆ ูƒู„ ุงู„ุนู†ุงุตุฑ ููŠ ุงู„ู€ sequence ุจูŠุญู‚ู‚ูˆุง ุงู„ุดุฑุท ุงู„ู„ูŠ ู…ุฏูŠู‡ูˆู„ู‡ุง.
  • ู„ูˆ ุงู„ู€ sequence ูุงุถูŠุฉุŒ ุจุชุฑุฌุน true (ู„ุฅู†ู‡ ู…ููŠุด ูˆู„ุง ุนู†ุตุฑ ู…ู‚ุฏุฑุด ูŠุญู‚ู‚ ุงู„ุดุฑุท!).
  • ุฏูŠ ุฒูŠ ุงู„ู€ TrueForAll in List
bool allEarnMoreThan4k = employees.All(e => e.Salary > 4000); // true (assuming sample data)
Console.WriteLine($"\nAll earn > 4k? {allEarnMoreThan4k}");
 
bool allAreMale = employees.All(e => e.Gender == "Male"); // false
Console.WriteLine($"All are male? {allAreMale}");
 
bool allSatisfyInEmpty = emptyList.All(x => x > 5); // true
Console.WriteLine($"All satisfy condition in empty list? {allSatisfyInEmpty}");

Contains()

  • ุจุชุฑุฌุน true ู„ูˆ ุงู„ู€ sequence ุจุชุญุชูˆูŠ ุนู„ู‰ ุนู†ุตุฑ ู…ุนูŠู† ุฃู†ุช ุจุชุฏูˆุฑ ุนู„ูŠู‡.
  • ุจุชุญุชุงุฌ ุชุนู…ู„ override ู„ู€ Equals/GetHashCode ู„ูˆ ุจุชุฏูˆุฑ ุนู„ู‰ object ู…ุฑูƒุจ.
  • ููŠู‡ overload ุจูŠุงุฎุฏ IEqualityComparer.
List<string> letters = new List<string> { "A", "B", "C" };
bool hasB = letters.Contains("B"); // true
Console.WriteLine($"\nLetters list contains 'B'? {hasB}");
bool hasX = letters.Contains("X"); // false
Console.WriteLine($"Letters list contains 'X'? {hasX}");
 
// Example with objects (needs Equals/GetHashCode override)
Product laptop = new Product { Id = 101, Name = "Laptop", Category = "Devices", Price = 25000 };
bool productListHasLaptop = products.Contains(laptop); // true (because we overrode Equals based on Id)
Console.WriteLine($"Products list contains laptop (Id 101)? {productListHasLaptop}");

SequenceEqual()

  • ุจุชู‚ุงุฑู† ุจูŠู† ุงุชู†ูŠู† sequences ุนุดุงู† ุชุดูˆู ู‡ู„ ู‡ู…ุง ู…ุชุณุงูˆูŠุชูŠู†.
  • ุจุชูƒูˆู† ู…ุชุณุงูˆูŠุฉ ู„ูˆ:
    1. ู„ูŠู‡ู… ู†ูุณ ุนุฏุฏ ุงู„ุนู†ุงุตุฑ.
    2. ูƒู„ ุนู†ุตุฑ ููŠ ุงู„ู€ sequence ุงู„ุฃูˆู„ู‰ ุจูŠุณุงูˆูŠ ุงู„ุนู†ุตุฑ ุงู„ู…ู‚ุงุจู„ ู„ู‡ ููŠ ู†ูุณ ุงู„ู€ index ููŠ ุงู„ู€ sequence ุงู„ุชุงู†ูŠุฉ (ุจุงุณุชุฎุฏุงู… Equals ุงู„ุงูุชุฑุงุถูŠ ุฃูˆ override ุฃูˆ IEqualityComparer).
List<int> seq1 = new List<int> { 1, 2, 3 };
List<int> seq2 = new List<int> { 1, 2, 3 };
List<int> seq3 = new List<int> { 1, 3, 2 }; // Different order
List<int> seq4 = new List<int> { 1, 2 };    // Different count

bool seq1EqualsSeq2 = seq1.SequenceEqual(seq2); // true
Console.WriteLine($"\nSequenceEqual(seq1, seq2)? {seq1EqualsSeq2}");
bool seq1EqualsSeq3 = seq1.SequenceEqual(seq3); // false (order matters)
Console.WriteLine($"SequenceEqual(seq1, seq3)? {seq1EqualsSeq3}");
bool seq1EqualsSeq4 = seq1.SequenceEqual(seq4); // false (count matters)
Console.WriteLine($"SequenceEqual(seq1, seq4)? {seq1EqualsSeq4}");

9. Zipping Operator (ุงู„ุฏู…ุฌ ุจุงู„ุชุฑุชูŠุจ)

ุนู†ุฏู†ุง operator ูˆุงุญุฏ ู‡ู†ุง ู‡ูˆ Zip(). (ุฏู‡ Deferred Execution).

Zip()

  • ุจูŠุฏู…ุฌ ุนู†ุตุฑ ุนู†ุตุฑ ู…ู† ุงุชู†ูŠู† sequences ู…ุน ุจุนุถ ุจู†ุงุกู‹ ุนู„ู‰ ุงู„ุชุฑุชูŠุจ (index).
  • ุจูŠุงุฎุฏ lambda expression ุจุชุญุฏุฏ ุฅุฒุงูŠ ุชุฏู…ุฌ ุงู„ุนู†ุตุฑ ู…ู† ุงู„ู€ sequence ุงู„ุฃูˆู„ู‰ ู…ุน ุงู„ุนู†ุตุฑ ุงู„ู…ู‚ุงุจู„ ู„ู‡ ููŠ ุงู„ู€ sequence ุงู„ุชุงู†ูŠุฉ ุนุดุงู† ุชู†ุชุฌ ุนู†ุตุฑ ุฌุฏูŠุฏ ููŠ ุงู„ู€ result sequence.
  • ุงู„ุนู…ู„ูŠุฉ ุจุชู‚ู ุฃูˆู„ ู…ุง ุฃู‚ุตุฑ sequence ู…ู† ุงู„ุงุชู†ูŠู† ุชุฎู„ุต. ุญุฌู… ุงู„ู€ result sequence ุจูŠูƒูˆู† ุจุญุฌู… ุฃู‚ุตุฑ sequence.
List<string> studentNames = new List<string> { "Amr", "Fatma", "Hassan", "Nour" };
List<int> studentScores = new List<int> { 85, 92, 78 }; // Shorter list
 
// Zip names and scores together
var studentInfo = studentNames.Zip(studentScores,
                                   (name, score) => $"{name} scored {score}");
// result sequence will have 3 elements only
 
Console.WriteLine("\nZipped Student Info (Zip):");
foreach (var info in studentInfo)
{
    Console.WriteLine(info);
}
// Output:
// Amr scored 85
// Fatma scored 92
// Hassan scored 78
// (Nour is ignored because studentScores ended)

10. Grouping Operators (ุงู„ุชุฌู…ูŠุน)

ุงู„ู€ Operator ุงู„ุฃุณุงุณูŠ ู‡ู†ุง ู‡ูˆ GroupBy(). ุจู†ุณุชุฎุฏู…ู‡ ุนุดุงู† ู†ุฌู…ุน ุนู†ุงุตุฑ ุงู„ู€ sequence ููŠ ู…ุฌู…ูˆุนุงุช ุจู†ุงุกู‹ ุนู„ู‰ key ู…ุนูŠู†. (ุฏู‡ Deferred Execution).

GroupBy()

  • ุจูŠุงุฎุฏ lambda expression ุจุชุญุฏุฏ ุงู„ู€ key ุงู„ู„ูŠ ู‡ูŠุชู… ุงู„ุชุฌู…ูŠุน ุนู„ู‰ ุฃุณุงุณู‡ (ู…ุซู„ู‹ุง ู†ุฌู…ุน ุงู„ู…ูˆุธููŠู† ุญุณุจ ุงู„ู€ Department).
  • ุจูŠุฑุฌุน sequence ุฌุฏูŠุฏุฉุŒ ูƒู„ ุนู†ุตุฑ ููŠู‡ุง ุนุจุงุฑุฉ ุนู† group.
  • ูƒู„ group ุจูŠูƒูˆู† ู„ูŠู‡ุง ุญุงุฌุชูŠู† ุฃุณุงุณูŠุชูŠู†:
    1. ุงู„ู€ Key: ุงู„ู‚ูŠู…ุฉ ุงู„ู„ูŠ ุชู… ุงู„ุชุฌู…ูŠุน ุจูŠู‡ุง (ู…ุซู„ู‹ุง ุงุณู… ุงู„ู‚ุณู… โ€œHRโ€).
    2. ุงู„ู€ IEnumerable<T>: ู…ุฌู…ูˆุนุฉ ุงู„ุนู†ุงุตุฑ ุงู„ุฃุตู„ูŠุฉ ุงู„ู„ูŠ ุจุชู†ุชู…ูŠ ู„ู„ู€ group ุฏูŠ (ู…ุซู„ู‹ุง ูƒู„ ุงู„ู…ูˆุธููŠู† ุงู„ู„ูŠ ููŠ ู‚ุณู… โ€œHRโ€). ุงู„ู€ group ู†ูุณู‡ุง ุจุชูƒูˆู† ู…ู† ู†ูˆุน IGrouping<TKey, TElement>.
  • ููŠู‡ ู†ุงุณ ุจุชูุถู„ ุชูƒุชุจ GroupBy ุจุงู„ู€ Query Syntax ู„ุฅู†ู‡ุง ู…ู…ูƒู† ุชูƒูˆู† ุฃูˆุถุญ ุดูˆูŠุฉ ู…ุน ูƒู„ู…ุฉ group by.

ู…ุซุงู„: ุชุฌู…ูŠุน ุงู„ู…ู†ุชุฌุงุช ุญุณุจ ุงู„ู€ Category:

Console.WriteLine("\n--- Grouping Operators ---");
 
// Group products by Category using Query Syntax (often clearer for grouping)
var productsByCategoryQuery = from p in products
                              group p by p.Category; // Group product 'p' by its 'Category' property
 
Console.WriteLine("Products Grouped by Category (Query Syntax):");
// productsByCategoryQuery is IEnumerable<IGrouping<string, Product>>
foreach (var categoryGroup in productsByCategoryQuery)
{
    Console.WriteLine($"Category: {categoryGroup.Key}"); // The Key is the Category name
    // categoryGroup itself is an IEnumerable<Product> for this category
    foreach (var product in categoryGroup)
    {
        Console.WriteLine($"- {product.Name} ({product.Price})");
    }
}
 
// Group products by Category using Fluent Syntax
var productsByCategoryFluent = products.GroupBy(p => p.Category);
 
Console.WriteLine("\nProducts Grouped by Category (Fluent Syntax):");
foreach (var categoryGroup in productsByCategoryFluent)
{
    Console.WriteLine($"Category: {categoryGroup.Key}");
    foreach (var product in categoryGroup)
    {
        Console.WriteLine($"- {product.Name} ({product.Price})");
    }
}

ุงุณุชุฎุฏุงู… into ู…ุน group by ููŠ ุงู„ู€ Query Syntax:

ุฒูŠ ู…ุง ุงุณุชุฎุฏู…ู†ุง into ู…ุน join ุนุดุงู† ู†ุนู…ู„ Left JoinุŒ ู…ู…ูƒู† ู†ุณุชุฎุฏู…ู‡ุง ู…ุน group by ุนุดุงู† ู†ูƒู…ู„ ุงู„ู€ query ุนู„ู‰ ุงู„ู€ groups ุงู„ู„ูŠ ุงุชูƒูˆู†ุช. ุจู†ุณุชุฎุฏู… into ุนุดุงู† ู†ุฏูŠ ุงุณู… ู„ู„ู€ group variable ูˆู†ู‚ุฏุฑ ู†ุนู…ู„ ุนู„ูŠู‡ where ุฃูˆ orderby ุฃูˆ select ุจุนุฏ ูƒุฏู‡.

ู…ุซุงู„: ู‡ุงุช ุงู„ู€ Categories ุงู„ู„ูŠ ููŠู‡ุง ุฃูƒุชุฑ ู…ู† ู…ู†ุชุฌ ูˆุงุญุฏ (Count > 1)ุŒ ูˆุฑุชุจู‡ู… ุฃุจุฌุฏูŠู‹ุงุŒ ูˆุงุนุฑุถ ุงุณู… ุงู„ู€ Category ูˆุนุฏุฏ ุงู„ู…ู†ุชุฌุงุช ููŠู‡ุง.

// Using Query Syntax with 'into' after 'group by'
var categoriesWithMoreThanOneProduct =
    from p in products                     // Start with products
    group p by p.Category                  // Group them by category
    into categoryGroup                     // Put the resulting group into 'categoryGroup' variable
    where categoryGroup.Count() > 1        // Filter the groups (keep only those with count > 1)
    orderby categoryGroup.Key              // Order the remaining groups by category name (the key)
    select new                             // Select the desired output
    {
        CategoryName = categoryGroup.Key,
        ProductCount = categoryGroup.Count()
    };
 
Console.WriteLine("\nCategories with more than 1 product (Query Syntax with into):");
foreach (var catInfo in categoriesWithMoreThanOneProduct)
{
    Console.WriteLine($"{catInfo.CategoryName}: {catInfo.ProductCount} products");
}
 
// Equivalent using Fluent Syntax (chaining methods)
var categoriesWithMoreThanOneProductFluent = products
    .GroupBy(p => p.Category)              // Group
    .Where(categoryGroup => categoryGroup.Count() > 1) // Filter groups
    .OrderBy(categoryGroup => categoryGroup.Key)       // Order groups
    .Select(categoryGroup => new            // Select output
    {
        CategoryName = categoryGroup.Key,
        ProductCount = categoryGroup.Count()
    });
 
Console.WriteLine("\nCategories with more than 1 product (Fluent Syntax):");
foreach (var catInfo in categoriesWithMoreThanOneProductFluent)
{
    Console.WriteLine($"{catInfo.CategoryName}: {catInfo.ProductCount} products");
}

11. Partitioning Operators (ุชู‚ุณูŠู… ุงู„ู€ Sequence)

ุงู„ู€ Operators ุฏูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ุนุดุงู† ู†ุงุฎุฏ ุฌุฒุก (partition) ู…ุนูŠู† ู…ู† ุงู„ู€ sequenceุŒ ูˆุบุงู„ุจู‹ุง ุจู†ุณุชุฎุฏู…ู‡ุง ููŠ Pagination (ุนุฑุถ ุงู„ุฏุงุชุง ุตูุญุฉ ุตูุญุฉ). (ุฏูˆู„ Deferred Execution).

Take(count)

  • ุจูŠุงุฎุฏ ุฃูˆู„ count ุนู†ุตุฑ ู…ู† ุจุฏุงูŠุฉ ุงู„ู€ sequence.
List<int> nums = Enumerable.Range(1, 10).ToList(); // 1 to 10
 
var firstThree = nums.Take(3); // 1, 2, 3
Console.WriteLine($"\nTake(3): {string.Join(", ", firstThree)}");

TakeLast(count) (.NET Standard 2.1+)

  • ุจูŠุงุฎุฏ ุขุฎุฑ count ุนู†ุตุฑ ู…ู† ู†ู‡ุงูŠุฉ ุงู„ู€ sequence.
var lastTwo = nums.TakeLast(2); // 9, 10
Console.WriteLine($"TakeLast(2): {string.Join(", ", lastTwo)}");

Skip(count)

  • ุจูŠุชุฎุทู‰ (skip) ุฃูˆู„ count ุนู†ุตุฑุŒ ูˆุจูŠุฑุฌุน ุจุงู‚ูŠ ุงู„ู€ sequence.
var skipFirstThree = nums.Skip(3); // 4, 5, 6, 7, 8, 9, 10
Console.WriteLine($"Skip(3): {string.Join(", ", skipFirstThree)}");

SkipLast(count) (.NET Standard 2.1+)

  • ุจูŠุชุฎุทู‰ ุขุฎุฑ count ุนู†ุตุฑุŒ ูˆุจูŠุฑุฌุน ุงู„ุฌุฒุก ุงู„ุฃูˆู„ุงู†ูŠ ู…ู† ุงู„ู€ sequence.
var skipLastTwo = nums.SkipLast(2); // 1, 2, 3, 4, 5, 6, 7, 8
Console.WriteLine($"SkipLast(2): {string.Join(", ", skipLastTwo)}");

TakeWhile(predicate)

  • ุจูŠุงุฎุฏ ุนู†ุงุตุฑ ู…ู† ุจุฏุงูŠุฉ ุงู„ู€ sequence ุทูˆู„ ู…ุง ุงู„ุดุฑุท (predicate) ู…ุชุญู‚ู‚.
  • ุจุชู‚ู ุชู…ุงู…ู‹ุง ุฃูˆู„ ู…ุง ุชู„ุงู‚ูŠ ุฃูˆู„ ุนู†ุตุฑ ู…ุด ุจูŠุญู‚ู‚ ุงู„ุดุฑุท. ุญุชู‰ ู„ูˆ ุงู„ุนู†ุงุตุฑ ุงู„ู„ูŠ ุจุนุฏู‡ ุจุชุญู‚ู‚ ุงู„ุดุฑุท ุชุงู†ูŠุŒ ู…ุด ุจุชุงุฎุฏู‡ู….
  • ู„ูŠู‡ overload ุจูŠุงุฎุฏ ุงู„ู€ index ูƒู…ุงู† (TakeWhile((element, index) => ...)).
int[] numbersMixed = { 1, 2, 3, 6, 7, 2, 8, 9 };
 
var takeWhileLessThan5 = numbersMixed.TakeWhile(n => n < 5); // 1, 2, 3 (stops at 6)
Console.WriteLine($"\nTakeWhile(n < 5): {string.Join(", ", takeWhileLessThan5)}");
 
var takeWhileIndexLessThan3 = numbersMixed.TakeWhile((n, index) => index < 3); // 1, 2, 3
Console.WriteLine($"TakeWhile(index < 3): {string.Join(", ", takeWhileIndexLessThan3)}");

SkipWhile(predicate)

  • ุจูŠุชุฎุทู‰ ุนู†ุงุตุฑ ู…ู† ุจุฏุงูŠุฉ ุงู„ู€ sequence ุทูˆู„ ู…ุง ุงู„ุดุฑุท (predicate) ู…ุชุญู‚ู‚.
  • ุจุชุจุฏุฃ ุชุงุฎุฏ ุงู„ุนู†ุงุตุฑ ุฃูˆู„ ู…ุง ุชู„ุงู‚ูŠ ุฃูˆู„ ุนู†ุตุฑ ู…ุด ุจูŠุญู‚ู‚ ุงู„ุดุฑุทุŒ ูˆุจุชุงุฎุฏ ุงู„ุนู†ุตุฑ ุฏู‡ ูˆูƒู„ ุงู„ู„ูŠ ุจุนุฏู‡ (ู…ู† ุบูŠุฑ ู…ุง ุชุนู…ู„ check ู„ู„ุดุฑุท ุชุงู†ูŠ).
  • ู„ูŠู‡ overload ุจูŠุงุฎุฏ ุงู„ู€ index ูƒู…ุงู†.
var skipWhileLessThan5 = numbersMixed.SkipWhile(n => n < 5); // 6, 7, 2, 8, 9 (skips 1, 2, 3, starts taking from 6)
Console.WriteLine($"\nSkipWhile(n < 5): {string.Join(", ", skipWhileLessThan5)}");
 
var skipWhileIndexLessThan3 = numbersMixed.SkipWhile((n, index) => index < 3); // 6, 7, 2, 8, 9
Console.WriteLine($"SkipWhile(index < 3): {string.Join(", ", skipWhileIndexLessThan3)}");

Chunk(size) (.NET 6+)

  • ุจุชู‚ุณู… ุงู„ู€ sequence ู„ู€ โ€œู‚ุทุนโ€ (chunks)ุŒ ูƒู„ ู‚ุทุนุฉ ุนุจุงุฑุฉ ุนู† array ุจุงู„ุญุฌู… (size) ุงู„ู„ูŠ ุญุฏุฏุชู‡ (ู…ุง ุนุฏุง ุขุฎุฑ ู‚ุทุนุฉ ู…ู…ูƒู† ุชูƒูˆู† ุฃุตุบุฑ).
  • ุจุชุฑุฌุน IEnumerable<T[]> (sequence of arrays).
var chunksOfThree = nums.Chunk(3); // [1,2,3], [4,5,6], [7,8,9], [10]
 
Console.WriteLine("\nChunk(3):");
foreach (var chunk in chunksOfThree)
{
    Console.WriteLine($"- [{string.Join(", ", chunk)}]");
}

ููƒุฑุฉ ุงู„ู€ Pagination

ุบุงู„ุจู‹ุง ุจู†ุณุชุฎุฏู… Skip() ูˆ Take() ู…ุน ุจุนุถ ุนุดุงู† ู†ุนู…ู„ Pagination. ุจูŠูƒูˆู† ุนู†ุฏูƒ:

  • ุงู„ู€ pageNumber: ุฑู‚ู… ุงู„ุตูุญุฉ ุงู„ู„ูŠ ุงู„ู…ุณุชุฎุฏู… ุนุงูŠุฒู‡ุง (ุจูŠุจุฏุฃ ู…ู† 1).
  • ุงู„ู€ pageSize: ุนุฏุฏ ุงู„ุนู†ุงุตุฑ ุงู„ู„ูŠ ุนุงูŠุฒ ุชุนุฑุถู‡ุง ููŠ ูƒู„ ุตูุญุฉ (ู…ุซู„ู‹ุง 10).

ุงู„ู…ุนุงุฏู„ุฉ ุจุชูƒูˆู†:

int pageNumber = 2; // Example: User wants page 2
int pageSize = 3;   // Example: Show 3 items per page
 
var paginatedResults = nums
                        .Skip((pageNumber - 1) * pageSize) // Skip items of previous pages
                        .Take(pageSize);                  // Take items for the current page
 
// For page 2, pageSize 3: Skip((2-1)*3) = Skip(3). Take(3). Result: 4, 5, 6
Console.WriteLine($"\nPagination (Page {pageNumber}, Size {pageSize}): {string.Join(", ", paginatedResults)}");

ู„ูŠู‡ ู…ุด ุจู†ุณุชุฎุฏู… Chunk() ู„ู„ู€ PaginationุŸ

  • ุงู„ู€ Chunk() ุจุชู‚ุณู… ุงู„ุฏุงุชุง ูƒู„ู‡ุง ุงู„ุฃูˆู„ ู„ู…ุฌู…ูˆุนุฉ ู…ู† ุงู„ู€ chunks ููŠ ุงู„ู€ memory. ุฏู‡ ู…ู…ูƒู† ูŠูƒูˆู† ู…ุด ูƒูˆูŠุณ ู„ูˆ ุงู„ุฏุงุชุง ุฌุงูŠุฉ ู…ู† database ุฃูˆ ุญุฌู…ู‡ุง ูƒุจูŠุฑ ุฌุฏู‹ุง. ุฅู†ุช ู…ุด ุนุงูŠุฒ ุชุญู…ู„ ูƒู„ ุงู„ุฏุงุชุง ุนุดุงู† ุชุงุฎุฏ ุตูุญุฉ ูˆุงุญุฏุฉ ุจุณ.
  • ุงู„ู€ Skip().Take() ุจุชุดุชุบู„ Deferred Execution ุจุดูƒู„ ุฃูุถู„. ู„ูˆ ุจุชุณุชุฎุฏู…ู‡ุง ู…ุน database (ุจุงุณุชุฎุฏุงู… IQueryable)ุŒ ุงู„ู€ EF Core ู‡ูŠุชุฑุฌู…ู‡ุง ู„ู€ SQL query ุจูŠุฌูŠุจ ุจุณ ุงู„ุฏุงุชุง ุจุชุงุนุฉ ุงู„ุตูุญุฉ ุงู„ู…ุทู„ูˆุจุฉ ู…ู† ุงู„ู€ database (ุฒูŠ ุงุณุชุฎุฏุงู… OFFSET FETCH ููŠ SQL Server)ุŒ ูˆุฏู‡ ุฃูƒูุฃ ุจูƒุชูŠุฑ.

12. Joins Operators (ุฑุจุท ุงู„ู€ Sequences)

ุงู„ู€ Operators ุฏูŠ ุจู†ุณุชุฎุฏู…ู‡ุง ุนุดุงู† ู†ุฑุจุท ุจูŠู† ุงุชู†ูŠู† sequences ุฃูˆ ุฃูƒุชุฑ ุจู†ุงุกู‹ ุนู„ู‰ key ู…ุดุชุฑูƒ ุจูŠู†ู‡ู…ุŒ ุฒูŠ ู…ุง ุจู†ุนู…ู„ JOIN ููŠ SQL.

ู…ู„ุญูˆุธุฉ ู…ู‡ู…ุฉ: Joins ู…ุน Local Sequences vs Databases

  • ูƒู†ุง ู…ู…ูƒู† ู†ุดุฑุญ ุงู„ู€ Joins ุฏูŠ ุนู„ู‰ local sequences (ุฒูŠ List<Employee> ูˆ List<Department> ููŠ ุงู„ุฐุงูƒุฑุฉ)ุŒ ุจุณ ูุงูŠุฏุชู‡ุง ุงู„ุญู‚ูŠู‚ูŠุฉ ูˆู‚ูˆุชู‡ุง ุจุชุธู‡ุฑ ุฃูƒุชุฑ ู„ู…ุง ุจู†ุณุชุฎุฏู…ู‡ุง ู…ุน database tables ู…ู† ุฎู„ุงู„ EF Core.
  • ู„ุฅู† ุงู„ู€ EF Core ุจูŠุชุฑุฌู… LINQ Joins ู„ู€ SQL Joins ุจุชุชู†ูุฐ ุนู„ู‰ ุงู„ู€ database server ู†ูุณู‡ุŒ ูˆุฏู‡ ุจูŠูƒูˆู† ูุนุงู„ ุฌุฏู‹ุง.

ุฅู…ุชู‰ ุจู†ุณุชุฎุฏู… ุงู„ู€ JoinุŸ

ุจู†ุณุชุฎุฏู…ู‡ุง ู„ู…ุง ู†ูƒูˆู† ู…ุญุชุงุฌูŠู† ู†ุฌูŠุจ ุฏุงุชุง ู…ุฑุชุจุทุฉ ุจุจุนุถู‡ุง ู…ู† ุฃูƒุชุฑ ู…ู† table ููŠ ู†ูุณ ุงู„ู€ query. ู…ุซู„ู‹ุงุŒ ู†ุฌูŠุจ ุงุณู… ุงู„ู…ูˆุธู ูˆุงุณู… ุงู„ู‚ุณู… ุงู„ู„ูŠ ุดุบุงู„ ููŠู‡.

ุงู„ู€ Join Operators ุงู„ุฃุณุงุณูŠุฉ

ุนู†ุฏู†ุง 2 operators ุฃุณุงุณูŠูŠู† ู„ู„ู€ Join ููŠ LINQ:

  1. ุงู„ู€ Join(): ุจู†ุณุชุฎุฏู…ู‡ุง ุนุดุงู† ู†ุนู…ู„ Inner Join. ุณู‡ู„ุฉ ูˆู…ุจุงุดุฑุฉ ู†ุณุจูŠู‹ุง.
  2. ุงู„ู€ GroupJoin(): ุจู†ุณุชุฎุฏู…ู‡ุง ูƒุฃุณุงุณ ู„ุนู…ู„ Left Outer Join (ูˆูƒู…ุงู† ู„ูŠู‡ุง ุงุณุชุฎุฏุงู… ุชุงู†ูŠ ู…ุน local sequences ู…ุด ู…ู‡ู… ุฃูˆูŠ ู…ุน databases).

(ู‡ู†ูุชุฑุถ ุฅู†ู†ุง ุนู†ุฏู†ุง DbContext ุงุณู…ู‡ context ููŠู‡ DbSet<Employee> ุงุณู…ู‡ Employees ูˆ DbSet<Department> ุงุณู…ู‡ Departments ู…ุฑุจูˆุทูŠู† ุจู€ database).


Join() Operator (ู„ู„ู€ Inner Join)

ุงู„ู€ Inner Join ุจูŠุฌูŠุจ ุจุณ ุงู„ุนู†ุงุตุฑ ุงู„ู…ุดุชุฑูƒุฉ ุจูŠู† ุงู„ู…ุฌู…ูˆุนุชูŠู†ุŒ ูŠุนู†ูŠ:

  • ุงู„ู…ูˆุธููŠู† ุงู„ู„ูŠ ู„ูŠู‡ู… DepartmentId ู…ุด null ูˆู…ูˆุฌูˆุฏ ูุนู„ู‹ุง ูƒู€ Id ููŠ Departments table.
  • ุงู„ุฃู‚ุณุงู… ุงู„ู„ูŠ ููŠู‡ุง ู…ูˆุธููŠู† ูุนู„ู‹ุง.

ูƒุชุงุจุฉ ุงู„ู€ Inner Join ุจู€ Query Syntax (ุงู„ุทุฑูŠู‚ุฉ ุงู„ู…ูุถู„ุฉ ู„ู„ู€ Joins)

ุงู„ู€ Query Syntax ุบุงู„ุจู‹ุง ุจุชูƒูˆู† ุฃุณู‡ู„ ููŠ ุงู„ู‚ุฑุงุกุฉ ูˆุงู„ูƒุชุงุจุฉ ู„ุนู…ู„ูŠุงุช ุงู„ู€ Join.

Console.WriteLine("\n--- Inner Join (Query Syntax) ---");
// Get Employee Name and Department Name for employees who have a department
 
var innerJoinResultQuery =
    from emp in context.Employees      // Start with Employees (can start with either)
    join dept in context.Departments // Join with Departments
    on emp.DepartmentId equals dept.Id // The JOIN CONDITION: FK == PK
    select new                         // Select the desired output
    {
        EmployeeName = emp.Name,
        DepartmentName = dept.Name
    };
 
// Execute and display
// Assuming context is an instance of your DbContext
// foreach (var item in innerJoinResultQuery)
// {
//     Console.WriteLine($"Employee: {item.EmployeeName}, Department: {item.DepartmentName}");
// }
Console.WriteLine("(Query would fetch matching employees and departments)");
 

ุดุฑุญ:

  1. ุงู„ู€ from emp in context.Employees: ุจู†ุจุฏุฃ ุจุงู„ู€ table ุงู„ุฃูˆู„.
  2. ุงู„ู€ join dept in context.Departments: ุจู†ู‚ูˆู„ู‡ ุงุนู…ู„ join ู…ุน ุงู„ู€ table ุงู„ุชุงู†ูŠ.
  3. ุงู„ู€ on emp.DepartmentId equals dept.Id: ุฏู‡ ุดุฑุท ุงู„ุฑุจุท. ู…ู‡ู…: ุงู„ุทุฑู ุงู„ุดู…ุงู„ (emp.DepartmentId) ู„ุงุฒู… ูŠูƒูˆู† ุงู„ู€ key ู…ู† ุงู„ู€ sequence ุงู„ู„ูŠ ุฌุงูŠุฉ ููŠ ุฌู…ู„ุฉ from ุงู„ุฃูˆู„ู‰ (emp)ุŒ ูˆุงู„ุทุฑู ุงู„ูŠู…ูŠู† (dept.Id) ู„ุงุฒู… ูŠูƒูˆู† ุงู„ู€ key ู…ู† ุงู„ู€ sequence ุงู„ู„ูŠ ุฌุงูŠุฉ ููŠ ุฌู…ู„ุฉ join (dept). ู„ูˆ ุนูƒุณุชู‡ู… ู…ู…ูƒู† ูŠุดุชุบู„ ุจุณ ุงู„ุฃูˆุถุญ ุชู…ุดูŠ ุจุงู„ุชุฑุชูŠุจ.
  4. ุงู„ู€ select new { ... }: ุจู†ุฎุชุงุฑ ุงู„ุญู‚ูˆู„ ุงู„ู„ูŠ ุนุงูŠุฒูŠู†ู‡ุง ู…ู† ุงู„ู€ emp ูˆุงู„ู€ dept.

ูƒุชุงุจุฉ ุงู„ู€ Inner Join ุจู€ Fluent Syntax

ู…ู…ูƒู† ู†ุนู…ู„ ู†ูุณ ุงู„ู€ Inner Join ุจุงู„ู€ Fluent SyntaxุŒ ุจุณ ุงู„ู€ syntax ุจุชุงุนู‡ุง ุจูŠูƒูˆู† ุฃุทูˆู„ ุดูˆูŠุฉ:

Console.WriteLine("\n--- Inner Join (Fluent Syntax) ---");
 
var innerJoinResultFluent = context.Employees // Start with the 'outer' sequence
    .Join(
        context.Departments, // The 'inner' sequence to join with
        emp => emp.DepartmentId, // Outer Key Selector (Key from the first sequence - emp)
        dept => dept.Id,         // Inner Key Selector (Key from the second sequence - dept)
        (emp, dept) => new       // Result Selector (Combines matching emp and dept)
        {
            EmployeeName = emp.Name,
            DepartmentName = dept.Name
        }
    );
 
// Execute and display (same result as Query Syntax)
// foreach (var item in innerJoinResultFluent)
// {
//     Console.WriteLine($"Employee: {item.EmployeeName}, Department: {item.DepartmentName}");
// }
Console.WriteLine("(Query would fetch matching employees and departments)");

ุดุฑุญ:

  1. ุงู„ู€ context.Employees.Join(...): ุจู†ุจุฏุฃ ุจุงู„ู€ sequence ุงู„ุฃูˆู„ู‰ ูˆู†ู†ุงุฏูŠ Join.
  2. ุงู„ู€ context.Departments: ุงู„ู€ parameter ุงู„ุฃูˆู„ ู‡ูˆ ุงู„ู€ sequence ุงู„ุชุงู†ูŠุฉ ุงู„ู„ูŠ ู‡ู†ุนู…ู„ join ู…ุนุงู‡ุง.
  3. ุงู„ู€ emp => emp.DepartmentId: ุงู„ู€ parameter ุงู„ุชุงู†ูŠ ู‡ูˆ lambda ุจุชุฎุชุงุฑ ุงู„ู€ key ู…ู† ุงู„ู€ sequence ุงู„ุฃูˆู„ู‰ (outer sequence).
  4. ุงู„ู€ dept => dept.Id: ุงู„ู€ parameter ุงู„ุชุงู„ุช ู‡ูˆ lambda ุจุชุฎุชุงุฑ ุงู„ู€ key ู…ู† ุงู„ู€ sequence ุงู„ุชุงู†ูŠุฉ (inner sequence).
  5. ุงู„ู€ (emp, dept) => new { ... }: ุงู„ู€ parameter ุงู„ุฑุงุจุน ู‡ูˆ lambda ุจุชุญุฏุฏ ุดูƒู„ ุงู„ู†ุชูŠุฌุฉ. ุจุชุงุฎุฏ ุนู†ุตุฑ ู…ู† ุงู„ุฃูˆู„ู‰ (emp) ูˆุนู†ุตุฑ ู…ู† ุงู„ุชุงู†ูŠุฉ (dept) ูƒู€ input ูˆุจุชุฑุฌุน ุงู„ู€ output ุงู„ู„ูŠ ุฅู†ุช ุนุงูŠุฒู‡.

ู‡ู„ ููŠู‡ ูุฑู‚ ุจูŠู† ุงู„ุทุฑูŠู‚ุชูŠู†ุŸ ู„ุฃุŒ ุงู„ุงุชู†ูŠู† ุจูŠุชุฑุฌู…ูˆุง ู„ู†ูุณ ุงู„ู€ INNER JOIN ููŠ SQL ูˆุจูŠุฏูˆุง ู†ูุณ ุงู„ู†ุชูŠุฌุฉ. ุงุณุชุฎุฏู… ุงู„ู„ูŠ ุชุฑูŠุญูƒุŒ ุจุณ ุงู„ู€ Query Syntax ุบุงู„ุจู‹ุง ุฃุณู‡ู„ ู„ู„ู€ Join.

ู…ู„ุญูˆุธุฉ ุนู† Overload ุงู„ู€ IEqualityComparer

  • ููŠู‡ overload ุชุงู†ูŠ ู„ู„ู€ method ุจุชุงุนุช Join ุจูŠุงุฎุฏ parameter ุฒูŠุงุฏุฉ ู…ู† ู†ูˆุน IEqualityComparer.
  • ุงุชูƒู„ู…ู†ุง ุนู† ุงู„ู€ interface ุฏู‡ ุฒู…ุงู† ู…ุน ุงู„ู€ Set Operators (ุฒูŠ Distinct, Unionโ€ฆ). ูุงูŠุฏุชู‡ ุฅู†ู‡ ุจูŠุฎู„ูŠูƒ ุชุชุญูƒู… ุฅุฒุงูŠ ุจูŠุชู… ู…ู‚ุงุฑู†ุฉ ุงู„ู€ objects.
  • ุงู…ุชู‰ ู…ู…ูƒู† ู†ุญุชุงุฌู‡ ู†ุธุฑูŠู‹ุงุŸ
    • ู„ู…ุง ุจู†ุนู…ู„ join ุจูŠู† local sequences (ู…ุด database tables) ูˆุงู„ู€ keys ุงู„ู„ูŠ ุจู†ู‚ุงุฑู†ู‡ุง ุนุจุงุฑุฉ ุนู† complex objects (ุฒูŠ class ุงุณู…ู‡ Address) ูˆู…ุด primitive types (ุฒูŠ int ุฃูˆ string). ููŠ ุงู„ุญุงู„ุฉ ุฏูŠุŒ ุงู„ู…ู‚ุงุฑู†ุฉ ุงู„ุนุงุฏูŠุฉ ู‡ุชู‚ุงุฑู† referencesุŒ ู„ูƒู† ุฅุญู†ุง ู…ู…ูƒู† ู†ูƒูˆู† ุนุงูŠุฒูŠู† ู†ู‚ุงุฑู† ุงู„ู€ values ุงู„ู„ูŠ ุฌูˆุง ุงู„ู€ objects. ุงู„ู€ IEqualityComparer ุจูŠุณู…ุญ ุจุฏู‡.
    • ุฃูˆ ููŠ ุญุงู„ุฉ ุงู„ู€ composite primary keys ุงู„ู…ุนู‚ุฏุฉ ุฌุฏู‹ุง (ุณูŠู†ุงุฑูŠูˆ ู†ุงุฏุฑ).
  • ู‡ู„ ุจู†ุญุชุงุฌู‡ ู…ุน ุงู„ู€ DatabaseุŸ
    • ู„ุฃุŒ ุบุงู„ุจู‹ุง ู…ุด ุจู†ุญุชุงุฌู‡ ุฎุงู„ุต. ู„ูŠู‡ุŸ ู„ุฃู† ุงู„ู€ Primary Keys ูˆุงู„ู€ Foreign Keys ููŠ ุงู„ู€ database ุจุชูƒูˆู† ุบุงู„ุจู‹ุง primitive types (int, string, Guidโ€ฆ) ูˆุงู„ู€ Entity Framework ุจูŠุนุฑู ูŠู‚ุงุฑู†ู‡ู… ุจุจุนุถ ุนุงุฏูŠ ุฌุฏู‹ุง ู…ู† ุบูŠุฑ IEqualityComparer.
    • ุงู„ู€ overload ุฏู‡ ุบุงู„ุจู‹ุง not translated ู„ู€ SQL ุจุดูƒู„ ุตุญูŠุญ ู„ูˆ ุญุงูˆู„ุช ุชุณุชุฎุฏู…ู‡ ู…ุน database query.
  • ุงู„ุฎู„ุงุตุฉ: ุงู†ุณู‰ ุงู„ู€ overload ุฏู‡ ุฏู„ูˆู‚ุชูŠุŒ ู…ุด ู‡ู†ุณุชุฎุฏู…ู‡ ู…ุน ุงู„ู€ database.

GroupJoin() Operator (ูˆุงุณุชุฎุฏุงู…ู‡ ู„ุนู…ู„ Left Join)

ู†ูŠุฌูŠ ุจู‚ู‰ ู„ู„ู€ operator ุงู„ุชุงู†ูŠุŒ ุงู„ู„ูŠ ู‡ูˆ GroupJoin. ุฏู‡ ู„ูŠู‡ ุงุณุชุฎุฏุงู… ู…ุนูŠู† ูˆู…ู…ูƒู† ูŠูƒูˆู† ู…ุฑุจูƒ ุดูˆูŠุฉ.

ุงุณุชุฎุฏุงู… ุงู„ู€ GroupJoin ุงู„ุฃุณุงุณูŠ (Join ุซู… Grouping by Object)

  • ุงู„ุงุณุชุฎุฏุงู… ุงู„ุฃุณุงุณูŠ ุฃูˆ ุงู„ููƒุฑุฉ ุงู„ุฃุตู„ูŠุฉ ูˆุฑุง GroupJoin ู‡ูŠ ุฅู†ูƒ ุชุนู…ู„ join ุจูŠู† two sequencesุŒ ูˆุจุนุฏูŠู† ุชุนู…ู„ grouping ู„ู„ู†ุชุงุฆุฌ.
  • ุงู„ุชุฑูƒุฉ ููŠู†ุŸ ุงู„ู€ Grouping ุงู„ู„ูŠ ุจูŠุนู…ู„ู‡ GroupJoin ุจูŠูƒูˆู† based on the entire object ู…ู† ุงู„ู€ outer sequenceุŒ ู…ุด based on a specific column.
  • ู…ุซุงู„: ู„ูˆ ุนู…ู„ุช GroupJoin ุจูŠู† Departments ูˆ EmployeesุŒ ู…ู…ูƒู† ุงู„ู†ุชูŠุฌุฉ ุชูƒูˆู† ูƒุฃู†ูƒ ุจุชู‚ูˆู„ โ€œู„ูƒู„ Department objectุŒ ู‡ุงุชู„ูŠ ู‚ุงูŠู…ุฉ ุจุงู„ู€ Employees ุจุชูˆุนู‡โ€.

ุชุฌุฑุจุฉ ุงู„ู€ GroupJoin ู…ุน ุงู„ู€ Database (ู…ุดูƒู„ุฉ ุงู„ุชุฑุฌู…ุฉ)

ุชุนุงู„ูˆุง ู†ุดูˆู ุดูƒู„ ุงู„ู€ fluent syntax ุจุชุงุน GroupJoin:

// Example starting with Departments to group by Department object
var groupJoinResult = context.Departments
    .GroupJoin(
        context.Employees,  // Inner sequence (Employees)
        d => d.Id,          // Outer Key Selector (PK of Department)
        e => e.DepartmentId, // Inner Key Selector (FK of Employee)
        (d, emps) => new    // Result Selector (takes department object, and IEnumerable of matching employees)
        {
            Department = d, // The Department object itself acts as the key for grouping
            Employees = emps // The collection of employees for that department
        }
    );
 
// Trying to iterate (this will likely throw an exception when hitting the database)
// foreach (var item in groupJoinResult)
// {
//     Console.WriteLine($"Department: {item.Department.Name}");
//     foreach (var emp in item.Employees)
//     {
//         Console.WriteLine($"  - Emp: {emp.Name}");
//     }
// }

ุดุฑุญ ุงู„ูƒูˆุฏ:

  1. ุงู„ู€ context.Departments.GroupJoin(...): ุจู†ุจุฏุฃ ุจุงู„ู€ DbSet ุงู„ู„ูŠ ุนุงูŠุฒูŠู† ู†ุนู…ู„ grouping ุนู„ู‰ ุฃุณุงุณ ุงู„ู€ objects ุจุชุงุนุชู‡ (ู‡ู†ุง Departments).
  2. ุงู„ู€ context.Employees, d => d.Id, e => e.DepartmentId: ุฏูˆู„ ุฒูŠ ุงู„ู€ Join ุงู„ุนุงุฏูŠ (ุงู„ู€ inner sequence ูˆุงู„ู€ keys).
  3. ุงู„ู€ (d, emps) => new { ... }: ุงู„ู€ result selector ู‡ู†ุง ู…ุฎุชู„ู.
    • ุงู„ู€ parameter ุงู„ุฃูˆู„ (d) ุจูŠู…ุซู„ ุงู„ู€ object ู…ู† ุงู„ู€ outer sequence (ุงู„ู€ Department object).
    • ุงู„ู€ parameter ุงู„ุชุงู†ูŠ (emps) ู…ุด ุจูŠู…ุซู„ employee ูˆุงุญุฏุŒ ู„ุฃ ุฏู‡ ุจูŠู…ุซู„ IEnumerable<Employee>ุŒ ูŠุนู†ูŠ ู‚ุงูŠู…ุฉ ุจูƒู„ ุงู„ู€ employees ุงู„ู„ูŠ ุงู„ู€ DepartmentId ุจุชุงุนู‡ู… ุจูŠุณุงูˆูŠ ุงู„ู€ Id ุจุชุงุน ุงู„ู€ Department ุงู„ุญุงู„ูŠ (d).
    • ุฑุฌุนู†ุง anonymous type ููŠู‡ ุงู„ู€ Department object ู†ูุณู‡ ูˆู…ุฌู…ูˆุนุฉ ุงู„ู€ Employees ุจุชุงุนุชู‡.

ุงู„ูุฑู‚ ุจูŠู† Cs IQueryable ูˆ Cs IEnumerableุŸ

ู…ู† ุงู„ุขุฎุฑ ู‡ู†ุง ุงู„ู€ GroupJoin ุชุนุชุจุฑ Cs Extension Methods ู„ู€ Queryable ุฃูˆ Enumerable ูุงู„ู„ูŠ ุจู†ูุฐู‡ู… ู…ู† Queryable ุฏูŠ ุจูŠู†ูุฐ ุงู„ุฃู…ุฑ ููŠ ุงู„ู€ Database ูˆูŠุฌูŠุจู„ูŠ ุงู„ุฏุงุชุง ุฎู„ุตุงู†ุฉ ู‡ู†ุง

ุงู†ู…ุง ุงู„ู€ Cs Enumerable ู‡ูŠุฌูŠุจู„ูŠ ุงู„ุฏุงุชุง ูƒู„ู‡ุง ุนู†ุฏูƒ ููŠ ุงู„ู€ Memory ูˆูŠุจุฏุฃ ูŠู†ูุฐ ุงู„ู€ Query ู‡ู†ุง

ุฅูŠู‡ ุงู„ู…ุดูƒู„ุฉ ู„ู…ุง ู†ุดุบู„ ุงู„ูƒูˆุฏ ุฏู‡ ุนู„ู‰ ุงู„ู€ DatabaseุŸ

  • ู„ู…ุง ุงู„ู€ Entity Framework Core ูŠุญุงูˆู„ ูŠุชุฑุฌู… ุงู„ู€ query ุฏู‡ ู„ู€ SQLุŒ ู‡ูŠูุดู„ ูˆู‡ูŠุถุฑุจ exception ุบุงู„ุจู‹ุง ุจุชู‚ูˆู„ could not be translated.
  • ู„ูŠู‡ุŸ ู„ุฃู† SQL ู…ููŠู‡ูˆุด ุญุงุฌุฉ ุงุณู…ู‡ุง ู†ุนู…ู„ grouping based on a whole record ุฃูˆ object. ุงู„ู€ GROUP BY ููŠ SQL ู„ุงุฒู… ูŠูƒูˆู† based on specific columns (ุฒูŠ DepartmentName ุฃูˆ DepartmentId).
  • ูู€ ุงู„ุงุณุชุฎุฏุงู… ุงู„ุฃุณุงุณูŠ ุฏู‡ ู„ู„ู€ GroupJoin ู…ูŠู†ูุนุด ู†ุทุจู‚ู‡ ู…ุจุงุดุฑุฉ ุนู„ู‰ ุงู„ู€ database.

ุงู„ุงุณุชุฎุฏุงู… ุฏู‡ ูŠู†ูุน ููŠู†ุŸ

  • ูŠู†ูุน ู„ูˆ ุดุบุงู„ูŠู† ุนู„ู‰ local sequences (ุฒูŠ List<Department> ูˆ List<Employee> ููŠ ุงู„ู€ memory). ุณุงุนุชู‡ุง ุงู„ู€ LINQ to Objects ู‡ูŠู‚ุฏุฑ ูŠุนู…ู„ grouping based on object ุนุงุฏูŠ.

ุงุณุชุฎุฏุงู… ุงู„ู€ GroupJoin ู„ุนู…ู„ Left Join (ุงู„ุทุฑูŠู‚ุฉ ุงู„ุฑุณู…ูŠุฉ)

ุงู„ู€ GroupJoin ู„ูˆุญุฏู‡ ู„ูŠู‡ ุงุณุชุฎุฏุงู… ุฃุณุงุณูŠ (ูŠุนู…ู„ join ูˆุจุนุฏูŠู† grouping based on the outer object)ุŒ ุจุณ ุฒูŠ ู…ุง ู‚ู„ู†ุงุŒ ุงู„ุงุณุชุฎุฏุงู… ุฏู‡ ู…ุด ุจูŠุชุฑุฌู… ูƒูˆูŠุณ ู„ู€ SQL.

ุงู„ูุงูŠุฏุฉ ุงู„ุญู‚ูŠู‚ูŠุฉ ู„ู„ู€ GroupJoin ู…ุน EF Core ู‡ูŠ ุฅู†ู‡ ุจูŠูƒูˆู† ุฎุทูˆุฉ ุฃุณุงุณูŠุฉ ุนุดุงู† ู†ุนู…ู„ Left Outer Join.

ุงู„ู€ Left Join ุจูŠุฌูŠุจ ูƒู„ ุนู†ุงุตุฑ ุงู„ู€ sequence ุงู„ุดู…ุงู„ (Left)ุŒ ูˆุงู„ุนู†ุงุตุฑ ุงู„ู…ุทุงุจู‚ุฉ ู„ูŠู‡ุง ู…ู† ุงู„ู€ sequence ุงู„ูŠู…ูŠู† (Right). ู„ูˆ ุนู†ุตุฑ ููŠ ุงู„ุดู…ุงู„ ู…ู„ูˆุด ู…ู‚ุงุจู„ ููŠ ุงู„ูŠู…ูŠู†ุŒ ุจูŠุฌูŠุจู‡ ุจุฑุถู‡ ุจุณ ุจูŠุญุท null (ุฃูˆ default) ู…ูƒุงู† ู‚ูŠู… ุงู„ูŠู…ูŠู†.

ู…ููŠุด method ู…ุจุงุดุฑุฉ ุงุณู…ู‡ุง .LeftJoin() ููŠ LINQ ุงู„ู‚ูŠุงุณูŠ ู†ู‚ุฏุฑ ู†ุณุชุฎุฏู…ู‡ุง ู…ุน EF Core. ุจู†ุนู…ู„ู‡ุง ุจุงุณุชุฎุฏุงู… GroupJoin ู…ุน SelectMany ูˆ DefaultIfEmpty.

ุนู…ู„ Left Join ุจู€ Query Syntax (ุจุงุณุชุฎุฏุงู… into) - ุงู„ุฃุณู‡ู„ ู„ู„ู‚ุฑุงุกุฉ

ุงู„ุทุฑูŠู‚ุฉ ุฏูŠ ู‡ูŠ ุงู„ุฃูˆุถุญ ู„ุนู…ู„ Left Join:

Console.WriteLine("\n--- Left Join (Query Syntax using 'into') ---");
// Get ALL Departments, and their corresponding Employees (or null if none)
 
var leftJoinQuery =
    from dept in context.Departments // Start with the LEFT table (Departments)
    join emp in context.Employees   // Join with the RIGHT table (Employees)
    on dept.Id equals emp.DepartmentId // Join condition
    into empGroup                   // *** Use 'into' to put matching employees into a temporary group ***
    from employeeInGroup in empGroup.DefaultIfEmpty() // *** Iterate the group, use DefaultIfEmpty() for departments with no employees ***
    select new
    {
        DepartmentName = dept.Name,
        // EmployeeName will be null if employeeInGroup is null (due to DefaultIfEmpty)
        EmployeeName = employeeInGroup == null ? "!!No Employees!!" : employeeInGroup.Name
    };
 
// Execute and display
// foreach (var item in leftJoinQuery)
// {
//     Console.WriteLine($"Department: {item.DepartmentName}, Employee: {item.EmployeeName}");
// }
Console.WriteLine("(Query would fetch all departments and their employees, showing 'No Employees' for empty depts)");
 

ุดุฑุญ ุงู„ู€ Magic:

  1. ุงู„ู€ from dept ... join emp ... on ...: ุฒูŠ ุงู„ู€ Inner Join ุนุงุฏูŠ.
  2. ุงู„ู€ into empGroup: ุฏูŠ ุฃู‡ู… ุญุชุฉ. ุจุฏู„ ู…ุง ุงู„ู€ join ูŠุฑุฌุน (dept, emp) ู„ูƒู„ ู…ุงุชุดุŒ ุจู†ู‚ูˆู„ู‡ ุญุท ูƒู„ ุงู„ู€ emp ุงู„ู„ูŠ ุจูŠู‚ุงุจู„ูˆุง ุงู„ู€ dept ุฏู‡ ููŠ ู…ุฌู…ูˆุนุฉ ู…ุคู‚ุชุฉ ุงุณู…ู‡ุง empGroup. ุงู„ู€ empGroup ุฏู‡ ู‡ูŠูƒูˆู† IEnumerable<Employee>.
  3. ุงู„ู€ from employeeInGroup in empGroup.DefaultIfEmpty(): ุจู†ุนู…ู„ loop ุชุงู†ูŠุฉ ุนู„ู‰ ุงู„ู€ empGroup ุฏู‡.
    • ุงู„ู€ DefaultIfEmpty(): ุฏูŠ ุจุชุนู…ู„ ุฅูŠู‡ุŸ ู„ูˆ ุงู„ู€ empGroup ูƒุงู† ูุงุถูŠ (ูŠุนู†ูŠ ุงู„ู‚ุณู… ุฏู‡ ู…ูƒู†ุด ู„ูŠู‡ ู…ูˆุธููŠู† ููŠ ุงู„ู€ join)ุŒ ุงู„ู€ method ุฏูŠ ุจุชุฑุฌุน sequence ููŠู‡ุง ุนู†ุตุฑ ูˆุงุญุฏ ุจุณ ู‚ูŠู…ุชู‡ null (ุฃูˆ ุงู„ู€ default ุจุชุงุน Employee). ู„ูˆ ุงู„ู€ empGroup ู…ุด ูุงุถูŠุŒ ุจุชุฑุฌุนู‡ ุฒูŠ ู…ุง ู‡ูˆ.
    • ูู„ู…ุง ู†ุนู…ู„ from employeeInGroup in ...ุŒ ู„ูˆ ุงู„ู‚ุณู… ู„ูŠู‡ ู…ูˆุธููŠู†ุŒ ุงู„ู€ loop ู‡ุชู„ู ุนู„ู‰ ูƒู„ ู…ูˆุธู ูˆ employeeInGroup ู‡ูŠุจู‚ู‰ ู‡ูˆ ุงู„ู…ูˆุธู ุฏู‡. ู„ูˆ ุงู„ู‚ุณู… ู…ููŠู‡ูˆุด ู…ูˆุธููŠู†ุŒ ุงู„ู€ loop ู‡ุชู„ู ู…ุฑุฉ ูˆุงุญุฏุฉ ุจุณ ูˆ employeeInGroup ู‡ูŠุจู‚ู‰ ู‚ูŠู…ุชู‡ null.
  4. ุงู„ู€ select new { ... }: ุจู†ุฎุชุงุฑ ุงู„ู†ุชูŠุฌุฉ. ุงู„ู€ dept.Name ุฌุงูŠ ู…ู† ุงู„ู€ from ุงู„ุฃูˆู„ู‰. ุงู„ู€ EmployeeName ุจู†ุงุฎุฏู‡ ู…ู† employeeInGroupุŒ ุจุณ ู„ุงุฒู… ู†ุนู…ู„ check ุฅู†ู‡ ู…ุด null ุงู„ุฃูˆู„.

ุนู…ู„ Left Join ุจู€ Fluent Syntax (ุจุงุณุชุฎุฏุงู… GroupJoin().SelectMany())

ุงู„ุทุฑูŠู‚ุฉ ุฏูŠ ุจุชุงุฏูŠ ู†ูุณ ุงู„ุบุฑุถุŒ ุจุณ ุงู„ู€ syntax ุจุชุงุนู‡ุง ุฃุนู‚ุฏ ุดูˆูŠุฉ:

Console.WriteLine("\n--- Left Join (Fluent Syntax using GroupJoin + SelectMany) ---");
 
var leftJoinFluent = context.Departments // Start with LEFT table
    .GroupJoin( // Step 1: GroupJoin
        context.Employees,   // Right table
        dept => dept.Id,           // Outer Key (Left)
        emp => emp.DepartmentId, // Inner Key (Right)
        (dept, empGroup) => new { Department = dept, Employees = empGroup } // Project to {Dept, GroupOfEmps}
    )
    .SelectMany( // Step 2: Flatten using SelectMany and handle empty groups
        deptAndGroup => deptAndGroup.Employees.DefaultIfEmpty(), // Apply DefaultIfEmpty to the employee group
        (deptAndGroup, employeeInGroup) => new // Result selector for SelectMany
        {
            DepartmentName = deptAndGroup.Department.Name,
            EmployeeName = employeeInGroup == null ? "!!No Employees!!" : employeeInGroup.Name
        }
    );
 
// Execute and display (same result as Query Syntax)
// foreach (var item in leftJoinFluent)
// {
//     Console.WriteLine($"Department: {item.DepartmentName}, Employee: {item.EmployeeName}");
// }
Console.WriteLine("(Query would fetch all departments and their employees, showing 'No Employees' for empty depts)");

ุดุฑุญ:

  1. ุจู†ุจุฏุฃ ุจู€ GroupJoin ุฒูŠ ู…ุง ุนู…ู„ู†ุงู‡ ู‚ุจู„ ูƒุฏู‡ุŒ ุจูŠุฑุฌุน sequence ู…ู† {Department, EmployeesGroup}.
  2. ุจู†ุณุชุฎุฏู… SelectMany ุนุดุงู† ู†ุนู…ู„ flatten.
  3. ุงู„ุฌุฒุก ุงู„ุฃูˆู„ ู…ู† SelectMany (deptAndGroup => deptAndGroup.Employees.DefaultIfEmpty()) ุจูŠุงุฎุฏ ูƒู„ group ู…ู† ุงู„ู…ูˆุธููŠู†ุŒ ูˆู„ูˆ ูุงุถูŠุฉ ุจูŠุฑุฌุน sequence ููŠู‡ุง null.
  4. ุงู„ุฌุฒุก ุงู„ุชุงู†ูŠ ู…ู† SelectMany ((deptAndGroup, employeeInGroup) => new { ... }) ุจูŠุงุฎุฏ ุงู„ู€ object ุงู„ุฃุตู„ูŠ (deptAndGroup) ูˆุจูŠุงุฎุฏ ูƒู„ ุนู†ุตุฑ ู…ู† ู†ุชูŠุฌุฉ ุงู„ู€ DefaultIfEmpty (ุงู„ู„ูŠ ู‡ูˆ ูŠุง Employee ูŠุง null)ุŒ ูˆุจูŠุนู…ู„ select ู„ู„ู†ุชูŠุฌุฉ ุงู„ู†ู‡ุงุฆูŠุฉ.

ุงู„ุฎู„ุงุตุฉ ู„ู„ู€ Left Join: ุงู„ู€ Query Syntax ุจุงุณุชุฎุฏุงู… into ุบุงู„ุจู‹ุง ุจุชูƒูˆู† ุฃุณู‡ู„ ูˆุฃูˆุถุญ ุจูƒุชูŠุฑ ู…ู† ุงู„ู€ Fluent Syntax ุจุงุณุชุฎุฏุงู… GroupJoin().SelectMany().


Cross Join (Cartesian Product)

ุงู„ู€ Cross Join ุจูŠุฌูŠุจ ูƒู„ ุงู„ุงุญุชู…ุงู„ุงุช ุงู„ู…ู…ูƒู†ุฉ ุจูŠู† ู…ุฌู…ูˆุนุชูŠู†ุŒ ูŠุนู†ูŠ ูƒู„ ุนู†ุตุฑ ู…ู† ุงู„ุฃูˆู„ู‰ ู…ุน ูƒู„ ุนู†ุตุฑ ู…ู† ุงู„ุชุงู†ูŠุฉ. (ุงุณุชุฎุฏุงู…ุงุชู‡ ู‚ู„ูŠู„ุฉ ููŠ ุงู„ู€ Business).

ุนู…ู„ Cross Join ุจู€ Query Syntax (ุงุชู†ูŠู† from)

ุงู„ุทุฑูŠู‚ุฉ ุจุณูŠุทุฉ ุฌุฏู‹ุง: ู…ุฌุฑุฏ ุงุชู†ูŠู† from ูˆุฑุง ุจุนุถ ู…ู† ุบูŠุฑ join ุฃูˆ where ุจูŠู†ู‡ู….

Console.WriteLine("\n--- Cross Join (Query Syntax) ---");
// Get every possible combination of Employee and Department
 
var crossJoinQuery =
    from emp in context.Employees   // First sequence
    from dept in context.Departments // Second sequence (NO 'join' or 'on')
    select new
    {
        EmployeeName = emp.Name,
        DepartmentName = dept.Name
    };
 
// Execute and display
// foreach (var item in crossJoinQuery)
// {
//     Console.WriteLine($"Employee: {item.EmployeeName}, Department: {item.DepartmentName}");
// }
Console.WriteLine("(Query would fetch all combinations of employees and departments)");
 

ุนู…ู„ Cross Join ุจู€ Fluent Syntax (SelectMany)

ุงู„ู€ Fluent Syntax ุงู„ู…ูƒุงูุฆ ู„ุงุชู†ูŠู† from ู‡ูˆ ุบุงู„ุจู‹ุง SelectMany.

Console.WriteLine("\n--- Cross Join (Fluent Syntax) ---");
 
var crossJoinFluent = context.Employees // Start with first sequence
    .SelectMany(
        emp => context.Departments, // For each employee, the collection to cross with is ALL departments
        (emp, dept) => new          // Result selector combining employee and department
        {
            EmployeeName = emp.Name,
            DepartmentName = dept.Name
        }
    );
 
// Alternative SelectMany structure (achieves the same)
var crossJoinFluentAlt = context.Employees
    .SelectMany(emp => context.Departments.Select(dept => new { emp, dept })) // Create pairs first
    .Select(pair => new { EmployeeName = pair.emp.Name, DepartmentName = pair.dept.Name }); // Select final
 
// Execute and display (same result as Query Syntax)
// foreach (var item in crossJoinFluent)
// {
//     Console.WriteLine($"Employee: {item.EmployeeName}, Department: {item.DepartmentName}");
// }
Console.WriteLine("(Query would fetch all combinations of employees and departments)");
 

ุงู„ุฎู„ุงุตุฉ ู„ู„ู€ Cross Join: ุงู„ู€ Query Syntax (ุงุชู†ูŠู† from) ุจุชูƒูˆู† ุฃูˆุถุญ ูˆุฃุณู‡ู„ ููŠ ุงู„ู‚ุฑุงุกุฉ.


ู†ู‚ุทุฉ ุฃุฎูŠุฑุฉ: ุงู…ุชู‰ ุฃุณุชุฎุฏู… Join ุตุฑูŠุญุฉ ุจุฏู„ .Include() ู„ู„ู€ ManyุŸ (ุนุดุงู† ุงู„ู€ Performance)

ู†ุฑุฌุน ุชุงู†ูŠ ู„ู†ู‚ุทุฉ ุงู„ู€ Eager Loading (.Include()) ู„ู„ู€ Navigational Property Many (ุฒูŠ ุญุงู„ุฉ Order ูˆ OrderItems ุงู„ู„ูŠ ู‚ู„ู†ุง ู„ุงุฒู… ู†ุนู…ู„ู‡ุง Eager Loading).

  • ู„ู…ุง ุจู†ุณุชุฎุฏู… .Include() ู…ุน Navigational Property ManyุŒ ุงู„ู€ Entity Framework Core ุจูŠุชุฑุฌู…ู‡ุง ู„ู€ SQL. ุฃุญูŠุงู†ู‹ุง (ู…ุด ุฏุงูŠู…ู‹ุง)ุŒ ุงู„ู€ SQL ุงู„ู†ุงุชุฌ ุฏู‡ ู…ู…ูƒู† ู…ูŠูƒูˆู†ุด ุงู„ุฃู…ุซู„ ู…ู† ู†ุงุญูŠุฉ ุงู„ู€ performance. ู…ู…ูƒู† ูŠุญุชูˆูŠ ุนู„ู‰ join ูˆู…ุนุงู‡ุง subquery ุฃูˆ ุทุฑูŠู‚ุฉ ุงู„ู€ join ู†ูุณู‡ุง ู…ุชูƒูˆู†ุด ุงู„ุฃูุถู„.
  • ุงู„ุญู„ (ููŠ ุญุงู„ุงุช ู†ุงุฏุฑุฉ ุฌุฏู‹ุง ู„ูˆ ุงู„ู€ Performance critical ุฃูˆูŠ):
    • ุจุฏู„ ู…ุง ุชุณุชุฎุฏู… .Include(o => o.OrderItems)ุŒ ู…ู…ูƒู† ุชูƒุชุจ ุงู„ู€ Join ุจูŠู† Orders ูˆ OrderItems ุจุฅูŠุฏูƒ (ุจุงุณุชุฎุฏุงู… Join operator ุฒูŠ ู…ุง ุดุฑุญู†ุง ููŠ ุงู„ุฃูˆู„).
    • ู„ูŠู‡ุŸ ุฏู‡ ู…ู…ูƒู† ูŠุฏูŠ ุงู„ู€ database query optimizer ุญุฑูŠุฉ ุฃูƒุจุฑ ุฅู†ู‡ ูŠุฎุชุงุฑ ุทุฑูŠู‚ุฉ ุงู„ู€ join ุงู„ุฃูุถู„ุŒ ุฃูˆ ูŠุชุฌู†ุจ ุงู„ู€ subquery ุงู„ู„ูŠ ู…ู…ูƒู† .Include() ุชุนู…ู„ู‡.
    • ุชุญุฐูŠุฑ: ุฏูŠ ุชุนุชุจุฑ advanced optimization. ู…ุชุนู…ู„ู‡ุงุด ุบูŠุฑ ู„ูˆ ุฃู†ุช ู…ุชุฃูƒุฏ ุฅู† .Include() ุนุงู…ู„ ู…ุดูƒู„ุฉ performance ุญู‚ูŠู‚ูŠุฉ ูˆู‚ุณุช ุงู„ูุฑู‚ ุจู†ูุณูƒ. ููŠ ู…ุนุธู… ุงู„ุญุงู„ุงุชุŒ .Include() ุจูŠูƒูˆู† ูƒุงููŠ ูˆู…ู‚ุฑูˆุก ุฃูƒุชุฑ.

ู…ุนู„ูˆู…ุงุช ุฅุถุงููŠุฉ (More Information)

let Keyword

  • ุจู†ุณุชุฎุฏู… let ุฌูˆู‡ ุงู„ู€ Query Syntax ุนุดุงู† ู†ุนุฑู variable ู…ุคู‚ุช ู†ู‚ุฏุฑ ู†ุฎุฒู† ููŠู‡ ู†ุชูŠุฌุฉ ุนู…ู„ูŠุฉ ุญุณุงุจูŠุฉ ุฃูˆ sub-expression ุนุดุงู† ู†ุณุชุฎุฏู…ู‡ุง ุฃูƒุชุฑ ู…ู† ู…ุฑุฉ ููŠ ู†ูุณ ุงู„ู€ query ุฃูˆ ุนุดุงู† ู†ุฎู„ูŠู‡ ู…ู‚ุฑูˆุก ุฃูƒุชุฑ.
  • ุงู„ู€ variable ุฏู‡ ุจูŠูƒูˆู† ู…ุชุงุญ ููŠ ุจุงู‚ูŠ ุฃุฌุฒุงุก ุงู„ู€ query ุงู„ู„ูŠ ุจุชูŠุฌูŠ ุจุนุฏ ุงู„ู€ let (ุฒูŠ where ุฃูˆ orderby ุฃูˆ select).

ู…ุซุงู„: ู‡ุงุช ุฃุณู…ุงุก ุงู„ู…ูˆุธููŠู† ุงู„ู„ูŠ ุงุณู…ู‡ู… (ุจุนุฏ ุชุญูˆูŠู„ู‡ ู„ู€ uppercase) ุจูŠุจุฏุฃ ุจุญุฑู โ€˜Aโ€™ุŒ ูˆุฑุชุจู‡ู… ุจุงู„ุงุณู… ุงู„ู€ uppercase ุฏู‡.

// Using 'let' in Query Syntax
var queryWithLet =
    from e in employees
    let upperCaseName = e.Name.ToUpper() // Define temporary variable
    where upperCaseName.StartsWith("A")  // Use the variable
    orderby upperCaseName                // Use the variable again
    select upperCaseName;                // Select the variable
 
Console.WriteLine("\nQuery with 'let':");
Console.WriteLine(string.Join(", ", queryWithLet)); // AHMED, ALI

into Keyword

ุงุชูƒู„ู…ู†ุง ุนู†ู‡ุง ููˆู‚ ู…ุน group by ูˆ join. ุงุณุชุฎุฏุงู…ู‡ุง ุงู„ุฃุณุงุณูŠ ู‡ูˆ ุฅู†ู‡ุง ุจุชูƒู…ู„ ุงู„ู€ query ุจุนุฏ ู…ุฑุญู„ุฉ ู…ุนูŠู†ุฉ (ุฒูŠ group ุฃูˆ join)ุŒ ูˆุจุชุนุฑู variable ุฌุฏูŠุฏ ู„ู„ู…ุฑุญู„ุฉ ุงู„ุฌุฏูŠุฏุฉ ุฏูŠ. ูƒุฃู†ู‡ุง ุจุชุนู…ู„ restart ู„ู„ู€ query ุจุณ ุจุงู„ู†ุชูŠุฌุฉ ุงู„ู…ุคู‚ุชุฉ ุงู„ู„ูŠ ูˆุตู„ุช ู„ู‡ุง.

  • ู…ุน group by ... into groupVariable: ุจู†ูƒู…ู„ ุดุบู„ ุนู„ู‰ ุงู„ู€ groups ุงู„ู„ูŠ ุงุชูƒูˆู†ุช.
  • ู…ุน join ... into groupVariable: ุจู†ูƒู…ู„ ุดุบู„ ุนู„ู‰ ุงู„ู€ groups ุงู„ู„ูŠ ุงุชูƒูˆู†ุช ุถู…ู†ูŠู‹ุง ุนุดุงู† ู†ุนู…ู„ ุบุงู„ุจู‹ุง Left Join.
  • ู…ุน select ... into variable: ู…ู…ูƒู† ุชุณุชุฎุฏู…ู‡ุง ุนุดุงู† ุชุงุฎุฏ ู†ุชูŠุฌุฉ select ูˆุชูƒู…ู„ ุนู„ูŠู‡ุง query ุชุงู†ูŠุŒ ุจุณ ุฏูŠ ุงุณุชุฎุฏุงู…ู‡ุง ุฃู‚ู„ ุดูŠูˆุนู‹ุง ู„ุฅู†ู†ุง ู…ู…ูƒู† ู†ุนู…ู„ chaining ุจุงู„ู€ Fluent Syntax ุฃุณู‡ู„.

ุงู„ูุฑู‚ ุจูŠู† let ูˆ into:

  • ุงู„ู€ let: ุจุชุนุฑู variable ุฌูˆู‡ ู†ูุณ ุงู„ู€ query scope ุนุดุงู† ุชุณุชุฎุฏู…ู‡ ููŠ ุงู„ุฃุฌุฒุงุก ุงู„ู„ูŠ ุจุงู‚ูŠุฉ ู…ู† ุงู„ู€ query ุฏู‡. ุจุชูƒู…ู„ ุงู„ู€ query ุจู†ูุณ ุงู„ู€ range variable ุงู„ุฃุตู„ูŠ + ุงู„ู€ variable ุงู„ุฌุฏูŠุฏ.
  • ุงู„ู€ into: ุจุชู†ู‡ูŠ ุงู„ู€ query scope ุงู„ุญุงู„ูŠ ูˆุชุจุฏุฃ scope ุฌุฏูŠุฏ ุจุงู„ู†ุชูŠุฌุฉ ุงู„ู„ูŠ ูˆุตู„ุช ู„ู‡ุง. ุงู„ู€ range variables ุงู„ู„ูŠ ูƒุงู†ุช ู‚ุจู„ into (ู…ุง ุนุฏุง ุงู„ู„ูŠ ููŠ ุฌู…ู„ุฉ into ู†ูุณู‡ุง) ู…ุจุชุจู‚ุงุด ู…ุชุงุญุฉ ุจุนุฏ into. ูƒุฃู†ู‡ุง ุจุชุนู…ู„ restart ู„ู„ู€ query.

ุงุณุชุฎุฏุงู… Regex ู…ุน LINQ

ู…ู…ูƒู† ู†ุณุชุฎุฏู… Regular Expressions (ุงู„ู„ูŠ ุงุชูƒู„ู…ู†ุง ุนู†ู‡ุง ู‚ุจู„ ูƒุฏู‡) ุฌูˆู‡ LINQ queries (ุฎุตูˆุตู‹ุง ู…ุน Select ุฃูˆ Where) ุนุดุงู† ู†ุนู…ู„ ุนู…ู„ูŠุงุช ู…ุนู‚ุฏุฉ ุนู„ู‰ ุงู„ู€ strings.

ู…ุซุงู„: ุดูŠู„ ูƒู„ ุงู„ุญุฑูˆู ุงู„ู…ุชุญุฑูƒุฉ (vowels) ู…ู† ุฃุณู…ุงุก ุงู„ู…ูˆุธููŠู†.

using System.Text.RegularExpressions; // Need this namespace
 
Console.WriteLine("\nUsing Regex with LINQ:");
 
List<string> namesList = employees.Select(e => e.Name).ToList(); // Get names
 
// Select names without vowels using Regex.Replace
var namesWithoutVowels = namesList.Select(name => Regex.Replace(name, "[aeiouAEIOU]", ""));
 
Console.WriteLine("Names without vowels:");
Console.WriteLine(string.Join(", ", namesWithoutVowels)); // Ahmd, Mn, Al, Sr
 
// Example: Filter names that become longer than 3 chars AFTER removing vowels using 'let'
var longNamesAfterNoVowelsLet =
    from name in namesList
    let noVowelName = Regex.Replace(name, "[aeiouAEIOU]", "")
    where noVowelName.Length > 3 // Check length of the result
    select noVowelName;
 
Console.WriteLine("\nLong names (>3) after removing vowels (let):");
Console.WriteLine(string.Join(", ", longNamesAfterNoVowelsLet)); // Ahmd
 
// Example: Filter names that become longer than 3 chars AFTER removing vowels using 'into'
var longNamesAfterNoVowelsInto =
    from name in namesList
    select Regex.Replace(name, "[aeiouAEIOU]", "") // Select the modified name
    into noVowelName // Put result into new variable, restarting query scope
    where noVowelName.Length > 3 // Filter based on the new variable
    select noVowelName;
 
Console.WriteLine("\nLong names (>3) after removing vowels (into):");
Console.WriteLine(string.Join(", ", longNamesAfterNoVowelsInto)); // Ahmd
 
 
// Equivalent using Fluent Syntax (often simpler here)
var longNamesAfterNoVowelsFluent = namesList
    .Select(name => Regex.Replace(name, "[aeiouAEIOU]", "")) // Transform
    .Where(noVowelName => noVowelName.Length > 3);           // Filter
 
Console.WriteLine("\nLong names (>3) after removing vowels (Fluent):");
Console.WriteLine(string.Join(", ", longNamesAfterNoVowelsFluent)); // Ahmd

ููŠ ุงู„ุญุงู„ุฉ ุฏูŠุŒ ุงุณุชุฎุฏุงู… Fluent Syntax ุฃูˆ Query Syntax ู…ุน let ุจูŠูƒูˆู† ุบุงู„ุจู‹ุง ุฃุณู‡ู„ ู…ู† ุงุณุชุฎุฏุงู… into.

ุงู„ู†ู‡ุงูŠุฉ (End)