Skip to main content

Best practice Generic List Filter using Func in C#

 In this Chapter we will learn about Func<x,y> delegate and its real time implementations and will see how we can create centralize functions to filter generic list.

Basic Definition

Func delegates offer a straightforward approach to defining and utilising methods by passing them as parameters and returning them as results.

  • Func<> is a delegate type for methods that return a value.
  • we can have up to 16 parameters, with the return type always being the last type parameter.
  • It’s useful for passing methods as arguments or working with lambda expressions in a clean and concise way.

Syntax

Consider below syntax, it has two parts left and right. Right side of lamba expression is return value and Left side of lamba expression is input parameters.

Example: This is simple code

using System;

class Program
{
static void Main()
{
// A Func delegate that adds two integers
Func<int, int, int> add = (x, y) => x + y;

int result = add(5, 10); // Calls the function, adds 5 and 10
Console.WriteLine("Sum: " + result); /// result will be 15
}
}

Advance Examples

a. Filtering Generic List using Func<>

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
// Sample list of employees
List<Employee> employees = new List<Employee>
{
new Employee { Id = 1, Name = "Devesh", Age = 30, Department = "HR", Salary = 60000 },
new Employee { Id = 2, Name = "Pankaj", Age = 40, Department = "IT", Salary = 80000 },
new Employee { Id = 3, Name = "Kapil Kumar", Age = 35, Department = "IT", Salary = 75000 },
new Employee { Id = 4, Name = "Shiv", Age = 25, Department = "Finance", Salary = 50000 },
new Employee { Id = 5, Name = "Shanker", Age = 50, Department = "HR", Salary = 95000 }
};

// Define a list of Func delegates to filter employees
List<Func<Employee, bool>> filters = new List<Func<Employee, bool>>
{
// Filter by age (e.g., employees aged 30 or older)
emp => emp.Age >= 30,

// Filter by department (e.g., IT department)
emp => emp.Department == "IT",

// Filter by salary (e.g., employees with salary over 70000)
emp => emp.Salary > 70000
};

// Apply each filter sequentially
foreach (var filter in filters)
{
Console.WriteLine("Filtered Employees:");
var filteredEmployees = employees.Where(filter).ToList();
foreach (var emp in filteredEmployees)
{
Console.WriteLine($"Id: {emp.Id}, Name: {emp.Name}, Age: {emp.Age}, Department: {emp.Department}, Salary: {emp.Salary}");
}
Console.WriteLine();
}
}
}

Understanding code

1. We have created List<Func<Employee, bool>> filters means here return type will be bool and Input will be Employee object

2. We are adding below expressions to List.

emp => emp.Age >= 30,

i) emp => emp.Age >= 30 filters employees aged 30 or older.
ii) emp => emp.Department == “IT” filters employees who are in the IT department.
iii) emp => emp.Salary > 70000 filters employees with a salary greater than 70,000.

Apply Filters

using below code we are passing all filter conditions added above and here we will be able to filter employee list object.

// Apply each filter sequentially
foreach (var filter in filters)
{
Console.WriteLine("Filtered Employees:");
var filteredEmployees = employees.Where(filter).ToList();
foreach (var emp in filteredEmployees)
{
Console.WriteLine($"Id: {emp.Id}, Name: {emp.Name}, Age: {emp.Age}, Department: {emp.Department}, Salary: {emp.Salary}");
}
Console.WriteLine();
}

b. Passing Func<> as parameter

Let’s modify above example and have code below

static List<Employee> FilterEmployees(List<Employee> employees, Func<Employee, bool> filter)
{
return employees.Where(filter).ToList();
}

We have passed Func<> as parameter in above code now

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
// Sample list of employees
List<Employee> employees = new List<Employee>
{
new Employee { Id = 1, Name = "Devesh", Age = 30, Department = "HR", Salary = 60000 },
new Employee { Id = 2, Name = "pankaj", Age = 40, Department = "IT", Salary = 80000 },
new Employee { Id = 3, Name = "vipin", Age = 35, Department = "IT", Salary = 75000 },
new Employee { Id = 4, Name = "Shiv", Age = 25, Department = "Finance", Salary = 50000 },
new Employee { Id = 5, Name = "Shanker", Age = 50, Department = "HR", Salary = 95000 }
};

}
}

Apply Filter

a. Filter by Age

// Way 1
var emp=FilterEmployees(employees, emp => emp.Age > 30);

//Way 2
Func<Employee, bool> filterByAge = emp => emp.Age > 30;
var olderEmployees = FilterEmployees(employees, filterByAge);

b. Filter by Salary

//Way 1
var emp = FilterEmployees(employees, emp => emp.Salary > 70000);


//way 2
Func<Employee, bool> filterBySalary = emp => emp.Salary > 70000;
var emp = FilterEmployees(employees, filterBySalary);

Benefits of Func<> : Centralize function for filter

I found we can utilize Func<> as centralize code for filtering we can create centralise code for filter and we can pass conditions based on requirement

let’s compare filtering with out Func<>

Bad Code

List<Employee> employees = new List<Employee>
{
new Employee { Id = 1, Name = "Devesh", Age = 30, Department = "HR", Salary = 60000 },
new Employee { Id = 2, Name = "pankaj", Age = 40, Department = "IT", Salary = 80000 },
new Employee { Id = 3, Name = "vipin", Age = 35, Department = "IT", Salary = 75000 },
new Employee { Id = 4, Name = "Shiv", Age = 25, Department = "Finance", Salary = 50000 },
new Employee { Id = 5, Name = "Shanker", Age = 50, Department = "HR", Salary = 95000 }
};

var emp=employees.where(x=>x.age>89 && r=>r.Deaprtment="HR" && y=>y.Salary>30000)

Problem with this code

we need to update code every time when we need to update conditions and this code hard to maintain

var emp=employees.where(x=>x.age>89 && r=>r.Deaprtment="HR" &&  y=>y.Salary>30000)

Good Code or Code with Func<>

Creation of centralize function

static List<Employee> FilterEmployees(List<Employee> employees, Func<Employee, bool> filter)
{
return employees.Where(filter).ToList();
}

Here in this code we are passing Func<> and this will work based on condition passed as above.

Thanks happy coding

Comments

Popular posts from this blog

Design Application using Clean Architecture

  Clean Architecture , introduced by  Robert C. Martin   (Uncle Bob), aims to create systems that are: Independent of frameworks Testable Independent of UI Independent of database Independent of any external agency Clean Architecture emphasizes separating the concerns of different parts of the system and ensuring that each part has a clear responsibility. .NET clean architecture as a development approach, available in a layered form to reduce dependency. The architecture consists of several layers, each with a specific role and dependencies that flow in one direction: from the outer layers to the inner layers. Inner most Layer is independent to its outer layer, means inner most layer does not have any references, it builds and stand independently. Dependency Rule The core principle of Clean Architecture is the  Dependency Rule , which states that source code dependencies can only point inward.  This means: Nothing in inner circle can depend on anything in an out...

How to Earn online from Medium.com

  As freelancer I started writing on medium (Tech blogs) from  Aug 2024   but I was already writing tech blogs on c-sharpcorner.com “The purpose of this post is to encourage new writers by helping them understand how they can earn as freelancers.” “Medium is a great platform for writers. When I started writing, I had no idea that I would reach the $100 benchmark in just four months. Now, I’m feeling self-inspired, as it has become a valuable source of income as a freelancer.” AUG 2024 ( $0 ) It was just beginning, and I posted 4 articles and had only few views 455 and 165 reads. During this time, I was learning about medium rules for writers and partner program. It will take some time to understand over all process. SEP 2024 ($6) As I started writing and I was getting few cents on Aug 2024, I posted 8 more articles in SEP, and it was good month because my blogs were getting noticed and I started getting claps etc. “This month, I went from $0 to $6, which was an achievemen...

Fixing High CPU Usage in .NET Core using Parallelism

  We will fix problem occurs due to incorrect use Parallelism in .NET Core To increase application performance sometimes we use process task or work extensively in Parallel and that may lead performance issue. When we do code, we should understand our requirement very carefully along with hardware resources those we have. We should code like that there should be less CPU usage and server should work without issues. In .NET Core, when you’re using parallelism (like Parallel.For, Task.WhenAll, or Task.Run), you might encounter performance issues if the number of concurrent threads or tasks exceeds what your system can efficiently handle. A common issue is high CPU usage or resource contention, which can degrade overall performance, cause excessive context switching, and even lead to thread starvation or deadlocks. Non members can access from here Effective Parallelism Strategies to Mitigate High CPU Usage in .NET Core We will fix problem occurs due to incorrect use Parallelism in .NE...