← Back to Articles         
What is the difference between Func, Action, and Predicate?

What is the difference between Func, Action, and Predicate?

Published on 12 Oct 2026     10 min read C#
Delegates, Events & Lambda Expressions
 

C# Delegates – Difference Between Func, Action, and Predicate

1. What are Func, Action, and Predicate?

In C#, Func, Action, and Predicate are built-in generic delegate types provided by .NET.

They are used to reference methods, lambda expressions, or anonymous methods without declaring custom delegates.

All three support passing methods as parameters, making code more reusable and flexible.

The main difference is their return type and purpose.

  • Func – Accepts input parameters and returns a value.

  • Action – Accepts input parameters and returns nothing (void).

  • Predicate – Accepts one input parameter and returns a Boolean (bool).

Basic Diagram

                  Delegates in C#
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
         Func          Action        Predicate
          |              |              |
          v              v              v
     Returns Value   Returns void    Returns bool
          |              |              |
          v              v              v
      Calculation     Perform Task    Check Condition
          |              |              |
          v              v              v
      Add Numbers     Print Message    Is Age >= 18?
 

2. What is Func in C#?

Definition

Func is a built-in generic delegate that accepts zero or more input parameters and returns a value.

The last generic type argument represents the return type.

Syntax

Func<TResult> function;

Func<T1, TResult> function;

Func<T1, T2, TResult> function;

Here:

  • T1, T2 represent input parameter types.

  • TResult represents the return type.

For example:

Func<int, int, int> add;

This delegate accepts two integers and returns an integer.

Example Program – Func

using System;

class Program
{
    static int Add(int a, int b)
    {
        return a + b;
    }

    static void Main()
    {
        Func<int, int, int> calculate = Add;

        int result = calculate(10, 20);

        Console.WriteLine($"Result: {result}");
    }
}

Output

Result: 30

Step-by-Step Explanation

Step 1: Define a method that accepts two integers and returns their sum.

static int Add(int a, int b)
{
    return a + b;
}

Step 2: Create a Func delegate referencing the method.

Func<int, int, int> calculate = Add;

The first two int types are input parameters, and the last int is the return type.

Step 3: Invoke the delegate.

int result = calculate(10, 20);

This invokes Add(10, 20) and returns 30.

Execution Flow

Func<int, int, int> calculate = Add
                  |
                  v
          calculate(10, 20)
                  |
                  v
             Add(10, 20)
                  |
                  v
              10 + 20
                  |
                  v
              return 30
                  |
                  v
             Result = 30

Using Func with a Lambda Expression

Instead of defining a separate method, we can use a lambda expression.

Func<int, int, int> add = (a, b) => a + b;

Console.WriteLine(add(10, 20));

Output:

30

Real-World Example – LINQ

Func is commonly used in LINQ to Objects.

List<int> numbers = new() { 10, 15, 20, 25, 30 };

Func<int, bool> isEven = n => n % 2 == 0;

var result = numbers.Where(isEven).ToList();

Console.WriteLine(string.Join(", ", result));

Output:

10, 20, 30

Explanation:

  • Func<int, bool> accepts an integer and returns true or false.

  • Where() uses the function to filter the collection.

  • Only even numbers are returned.

Note: Enumerable.Where() accepts a Func<T, bool> overload. In EF Core, IQueryable.Where() commonly uses Expression<Func<T, bool>>, allowing the expression to be translated into SQL.

Key Points – Func

  1. Func always returns a value.

  2. The final generic argument specifies the return type.

  3. It supports zero to sixteen input parameters in standard .NET generic delegate overloads.

  4. It can reference compatible methods or lambda expressions.

  5. It is widely used in LINQ, callbacks, and functional programming.

  6. A Func<T, bool> can be used for conditions, just like a predicate.

 

3. What is Action in C#?

Definition

Action is a built-in delegate used to reference methods that do not return a value.

Its return type is always void.

It is commonly used for operations such as logging, printing, sending notifications, and executing callbacks.

Syntax

Action action;

Action<T1> action;

Action<T1, T2> action;

For example:

Action<string> display;

This delegate accepts a string parameter and returns nothing.

Example Program – Action

using System;

class Program
{
    static void DisplayMessage(string message)
    {
        Console.WriteLine(message);
    }

    static void Main()
    {
        Action<string> display = DisplayMessage;

        display("Welcome to C#");
    }
}

Output

Welcome to C#

Step-by-Step Explanation

Step 1: Define a method with a void return type.

static void DisplayMessage(string message)
{
    Console.WriteLine(message);
}

Step 2: Assign the method to an Action delegate.

Action<string> display = DisplayMessage;

Step 3: Invoke the delegate.

display("Welcome to C#");

The delegate executes DisplayMessage().

Execution Flow

Action<string> display = DisplayMessage
                  |
                  v
       display("Welcome to C#")
                  |
                  v
       DisplayMessage(message)
                  |
                  v
       Console.WriteLine(message)
                  |
                  v
       Prints "Welcome to C#"
                  |
                  v
             Returns void

Using Action with Lambda Expression

Action<string> greet = name =>
{
    Console.WriteLine($"Hello {name}");
};

greet("John");

Output:

Hello John

Real-World Example – Logging

In an application, we can pass a logging operation as an Action.

using System;

class Program
{
    static void ProcessPayment(
        decimal amount,
        Action<string> logger)
    {
        logger($"Processing payment: {amount}");

        Console.WriteLine("Payment processed successfully.");

        logger("Payment processing completed.");
    }

    static void Main()
    {
        Action<string> log = message =>
        {
            Console.WriteLine($"LOG: {message}");
        };

        ProcessPayment(1000m, log);
    }
}

Output

LOG: Processing payment: 1000
Payment processed successfully.
LOG: Payment processing completed.

Explanation

The ProcessPayment() method accepts an Action<string> as a parameter.

Instead of implementing its own logging mechanism, it invokes the supplied delegate.

This allows different logging implementations to be supplied without changing the payment method.

For production ASP.NET Core applications, ILogger<T> is generally preferred for logging because it provides structured logging, severity levels, and integration with logging providers.

Key Points – Action

  1. Action always returns void.

  2. It supports zero to sixteen input parameters.

  3. It is useful for performing operations without returning results.

  4. It can reference void methods or compatible lambda expressions.

  5. It is commonly used for callbacks, notifications, and simple logging operations.

  6. Unlike Func, it does not have a generic return-type parameter.

 

4. What is Predicate in C#?

Definition

Predicate<T> is a built-in generic delegate that accepts one input parameter and returns a Boolean value (true or false).

It is mainly used to evaluate conditions.

Syntax

Predicate<T> predicate;

For example:

Predicate<int> isAdult;

This delegate accepts an integer and returns a Boolean.

Example Program – Predicate

using System;

class Program
{
    static bool IsAdult(int age)
    {
        return age >= 18;
    }

    static void Main()
    {
        Predicate<int> checkAge = IsAdult;

        Console.WriteLine(checkAge(25));
        Console.WriteLine(checkAge(15));
    }
}

Output

True
False

Step-by-Step Explanation

Step 1: Define a method that evaluates a condition.

static bool IsAdult(int age)
{
    return age >= 18;
}

Step 2: Create a predicate delegate.

Predicate<int> checkAge = IsAdult;

Step 3: Invoke the predicate.

checkAge(25);

Since 25 >= 18, the method returns true.

Execution Flow

Predicate<int> checkAge = IsAdult
                 |
                 v
            checkAge(25)
                 |
                 v
             IsAdult(25)
                 |
                 v
             Is 25 >= 18?
                 |
              +--+--+
              |     |
             Yes    No
              |     |
              v     v
             True  False

Using Predicate with Lambda Expression

Predicate<int> isEven = number => number % 2 == 0;

Console.WriteLine(isEven(10));
Console.WriteLine(isEven(15));

Output:

True
False

Real-World Example – List Filtering

Predicate<T> is commonly used with List<T>.Find(), FindAll(), Exists(), and RemoveAll().

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> ages = new() { 15, 20, 17, 25, 30 };

        Predicate<int> isAdult = age => age >= 18;

        List<int> adults = ages.FindAll(isAdult);

        Console.WriteLine(string.Join(", ", adults));
    }
}

Output

20, 25, 30

Explanation

The FindAll() method accepts a Predicate<int>.

For every number in the list, the predicate checks whether the age is greater than or equal to 18.

Only matching values are returned.

Key Points – Predicate

  1. Predicate<T> always returns bool.

  2. It accepts exactly one input parameter.

  3. It is designed for condition checking.

  4. It is commonly used with List<T> filtering and searching methods.

  5. It is functionally similar to Func<T, bool>, although the delegate types are different.

  6. A Predicate<T> variable cannot be directly passed where Func<T, bool> is required without an appropriate conversion or wrapper.

 

5. Difference Between Func, Action, and Predicate

Feature

Func

Action

Predicate

Return type

Any specified type

void

bool

Input parameters

0–16

0–16

Exactly 1

Primary purpose

Calculate/return a result

Perform an operation

Evaluate a condition

Generic syntax

Func<T, TResult>

Action<T>

Predicate<T>

LINQ usage

Very common

Not normally used for LINQ filtering

Some list methods

Example

Add numbers

Print message

Check age

Simple Comparison Program

The following program demonstrates all three delegate types together.

using System;

class Program
{
    static void Main()
    {
        // Func - Returns a value
        Func<int, int, int> add = (a, b) => a + b;

        // Action - Returns void
        Action<string> display = message =>
            Console.WriteLine(message);

        // Predicate - Returns bool
        Predicate<int> isEven = number =>
            number % 2 == 0;

        int result = add(10, 20);

        display($"Addition Result: {result}");

        bool check = isEven(result);

        display($"Is Even: {check}");
    }
}

Output

Addition Result: 30
Is Even: True

Execution Flow

                 Main()
                    |
                    v
        Func<int, int, int>
                    |
                    v
              Add(10, 20)
                    |
                    v
                Result 30
                    |
                    v
             Action<string>
                    |
                    v
          Print Addition Result
                    |
                    v
             Predicate<int>
                    |
                    v
             Is 30 Even?
                    |
                    v
                  True
                    |
                    v
             Action<string>
                    |
                    v
            Print Is Even
 

6. Important Interview Questions

Q1. Can Func return a Boolean value?

Yes.

Func<int, bool> isEven = x => x % 2 == 0;

A Func<T, bool> performs the same kind of condition checking as Predicate<T>.

Q2. Can Action return a value?

No. Action represents methods with a void return type.

If you need a return value, use Func.

Q3. Can Predicate accept multiple parameters?

No. Predicate<T> accepts exactly one parameter.

If you need multiple parameters and a Boolean result, use Func.

Func<int, int, bool> isGreater = (a, b) => a > b;

Q4. What is the difference between Predicate<T> and Func<T, bool>?

Both accept one input and return a Boolean.

Predicate<int> p = x => x > 10;

Func<int, bool> f = x => x > 10;

The difference is primarily their delegate types and the APIs that accept them.

  • Predicate<T> is commonly used in List<T> methods such as FindAll().

  • Func<T, bool> is commonly used in LINQ to Objects methods such as Where().

Q5. Are Func, Action, and Predicate delegates or interfaces?

All three are delegate types, not interfaces.

They are declared in the System namespace.

Q6. What is the difference between a custom delegate and built-in delegates?

Custom delegates allow us to define a specific method signature and meaningful delegate name.

Built-in delegates reduce the need to create custom delegate declarations for common signatures.

For example:

// Custom delegate
public delegate int Calculate(int a, int b);

// Built-in delegate with equivalent signature
Func<int, int, int> calculate;
 

7. Key Points for Interviews

  1. Func, Action, and Predicate are built-in delegates.

  2. Func returns a value and is frequently used in LINQ.

  3. Action returns void and is commonly used for callbacks.

  4. Predicate returns bool and is commonly used for filtering conditions.

  5. Func<T, bool> and Predicate<T> can represent equivalent conditional logic.

  6. All three support lambda expressions and method groups.

  7. Delegates provide a way to pass executable behavior to another method.

  8. They help reduce coupling and support reusable code.

  9. Delegates can reference instance or static methods.

  10. They are useful in functional programming, LINQ, and callback-based application design.

8. Interview-Ready Answer

Func, Action, and Predicate are built-in delegate types in C#.

Func is used when a method returns a value. Its last generic parameter represents the return type.

Action is used when a method performs an operation without returning a value.

Predicate is used to evaluate a condition. It accepts one parameter and always returns a Boolean.

For example, in an application, we can use Func to calculate an amount, Action to execute a notification callback, and Predicate to validate a condition.

Easy way to remember:

Func      = Input -> Output
Action    = Input -> No Output (void)
Predicate = Input -> True / False
← Back to Articles