Func, Action & Predicate – Generic Delegates

Introduction

In an earlier post, we have discussed delegates, multicast delegate. In this article, I am going to discuss the Generic Delegates in C#.

In .NET Framework 3.5, C# introduces Generic delegate which allows to invoke the delegates without defining the delegate instance. To understand the Generic Delegates, we should have the basic knowledge of Delegates. I would recommend checking earlier posts related to delegates, multicast delegate.

The Func , Action, and Predicate are the three generic delegates and are available in System namespace. We can make use of all these three predefined generic delegates when we want to invoke the methods without defining the delegates explicitly.

Let’s understand why we need generic delegates? For example, suppose we have class which contain below methods:

public int NumPower(int x, int y) – this method returns the power of x int y times.
public void Sequer(int x) – this method returns the square of the value passed to it.
public void Print(int x) – This method accepts the value and prints the message.
public bool IsPrimeNumber(int x) – this method returns true if the value passed to it is prime, else it returns false.

namespace Operations

{
    class MathOperation
    {
        public int NumPower(int x, int y)
        {
            var result = x;
            for (var i = 1; i < y; i++)
            {
                result *= x;
            }

            return result;
        }

        public int Sequer(int x)
        {
            return x * x;
        }

	 
	 public void Print(int x)
        {
            Console.WriteLine($"In MathOperation {x}");
        }
	
        public bool IsPrimeNumber(int x)
        {
            if (x==1)
                return true;

            for (var i = 2; i < x; i++)
            {
                if (x%i==0)
                    return true;
            }

            return false;
        }
    }
}

Now to call these methods through delegate, we need to define 4 delegates as signature of these four methods are different.

The program to call these methods through delegate:

using System;

namespace Operations

{

    public delegate int NumPowerDelegate(int a, int b);

    public delegate int SequerDelegate(int x);

    public delegate bool IsPrimeNumberDelegate(int x);

    public delegate void PrintDelegate(int x);

    class Program
    {
        static void Main()
        {
            var p = new MathOperation();

            NumPowerDelegate obj1 = p.NumPower;
            SequerDelegate obj2 = p.Sequer;
            IsPrimeNumberDelegate obj3 = p.IsPrimeNumber;
            PrintDelegate obj4 = p. Print;

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            Obj4(10);

            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }
}

So, we had defined 4 delegates to call our 4 methods, and the reason was that the signature of all 4 methods is different. Now C# provides the generic delegates which allow to invoke the method with defining delegate instance.

Func

Func is a generic delegate, we use this delegate when a method we have defined returns a value, the value can be of any type. It takes one or more input parameters and returns one out parameter. The last parameter is considered as a return value.

Func delegate type can include 0 to 16 input parameters of different types. It must have one return type. So, the return type is mandatory but the input parameter is not.

Just remember that in the “Func” predicate, the last parameter within the angled braces “< >” will be the return type.

Let’s call the above methods using Func
public int NumPower(int x, int y) – we can call this method using func as it returns the value. Below is func syntax to call NumPower method
Func NumPower;
• public void Sequer(int x) – we can call this method using func as it returns the value. Below is func syntax to call Sequer method
Func NumPower;
public void Print(int x) – We can not call this method using Func as it does not return value.
public bool IsPrimeNumber(int x) – we can call this method using func as it returns the value. Below is func syntax to call IsPrimeNumber method
Func NumPower;

Here is program class code:

using System;

namespace Operations
{
    public delegate void PrintDelegate(int x);

    class Program
    {
        static void Main()
        {
            var p = new MathOperation();

            var obj1 = new Func<int, int, int>(p.NumPower);
            var obj2 = new Func<int, int>(p.Sequer);
            var obj3 = new Func<int, bool>(p.IsPrimeNumber);
            PrintDelegate obj4 = p.Print;

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }
}

Func with an Anonymous Method

We can assign an anonymous method to the Func delegate by using the delegate keyword.
Let’s change the main class to use func with an Anonymous Method, so that required method logic will move to the main class


using System;

namespace Operations
{
    public delegate void PrintDelegate(int x);

    class Program
    {
        static void Main()
        {
            var p = new MathOperation();

            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


            Func<int, bool> obj3 = delegate (int x)
            {
                if (x == 1)
                    return true;

                for (var i = 2; i < x; i++)
                {
                    if (x % i == 0)
                        return true;
                }

                return false;
            };

            PrintDelegate obj4 = p.Print;

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }


    class MathOperation
    {
        public void Print(int x)
        {
            Console.WriteLine($"In MathOperation {x}");
        }
    }
}

Func with Lambda Expression

A Func delegate can also be used with a lambda expression, lets change above class to use lambda expression

Source code:

using System;

namespace Operations
{
    public delegate void PrintDelegate(int x);

    class Program
    {
        static void Main()
        {
            var p = new MathOperation();

            Func<int, int, int> obj1 = (x, y) =>
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = x => x * x;


            Func<int, bool> obj3 = x =>
            {
                if (x == 1)
                    return true;

                for (var i = 2; i < x; i++)
                {
                    if (x % i == 0)
                        return true;
                }

                return false;
            };

            PrintDelegate obj4 = p.Print;

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }

class MathOperation
    {
        public void Print(int x)
        {
            Console.WriteLine($"In MathOperation {x}");
        }

    }
}

Func Overview:

• Func is built-in delegate type.
• Func delegate type must return a value.
• Func delegate type can have zero to 16 input parameters.
• Func delegate does not allow ref and out parameters.
• Func delegate type can be used with an anonymous method or lambda expression.

Action

we use this delegate when a method we have defined does not return any value, i.e. the return type of the method is “void”. It takes one or more input parameters and returns nothing.

Similar to func it takes 16 input parameter.

From above example only one method does not return anything i.e. public void Print(int x). So, for calling this method, we can use the “Action” delegate.

Let’s add the action delegate in above program

Source Code:

using System;

namespace Operations
{

    class Program
    {
        static void Main()
        {
            var p = new MathOperation();

            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


            Func<int, bool> obj3 = delegate (int x)
            {
                if (x == 1)
                    return true;

                for (var i = 2; i < x; i++)
                {
                    if (x % i == 0)
                        return true;
                }

                return false;
            };

            Action<int> obj4 = p.Print;

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }


    class MathOperation
    {
        public void Print(int x)
        {
            Console.WriteLine($"In MathOperation {x}");
        }
    }
}

Action with an Anonymous Method

An Anonymous method can also be assigned to an Action delegate, lets see below source code with above example

using System;

namespace Operations
{

    class Program
    {
        static void Main()
        {

            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


            Func<int, bool> obj3 = delegate (int x)
            {
                if (x == 1)
                    return true;

                for (var i = 2; i < x; i++)
                {
                    if (x % i == 0)
                        return true;
                }

                return false;
            };

            Action<int> obj4 = delegate(int x) { Console.WriteLine($"In MathOperation {x}"); };

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }
}

Action with Lambda Expression

A Lambda expression also can be used with an Action delegate, let’s see below source code with above example

using System;

namespace Operations
{

    class Program
    {
        static void Main()
        {

            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


            Func<int, bool> obj3 = delegate (int x)
            {
                if (x == 1)
                    return true;

                for (var i = 2; i < x; i++)
                {
                    if (x % i == 0)
                        return true;
                }

                return false;
            };

            Action<int> obj4 = x => Console.WriteLine($"In MathOperation {x}");

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }
}

Action Overview:

• Action delegate is same as func delegate except that it does not return anything. Return type must be void.
• Action delegate can have 0 to 16 input parameters.
• Action delegate can be used with anonymous methods or lambda expressions.


Predicate

we use this delegate when a method we have defined returns a boolean value, i.e. either “true” or “false”. A predicate delegate method must take one input parameter and return a boolean – true or false.

In above program “IsPrimeNumber(int x)”returns a “bool” value. So, for calling this method, we can use the “Predicate” delegate.

Source code

using System;

namespace Operations
{

    class Program
    {
        static void Main()
        {
            var p = new MathOperation();
            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


            Predicate<int> obj3 = p.IsPrimeNumber;

            Action<int> obj4 = x => Console.WriteLine($"In MathOperation {x}");

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }

    class MathOperation
    {

        public bool IsPrimeNumber(int x)
        {
            if (x == 1)
                return true;

            for (var i = 2; i < x; i++)
            {
                if (x % i == 0)
                    return true;
            }

            return false;
        }
    }

}

Predicate with anonymous method

An anonymous method can also be assigned to a Predicate delegate type as shown below.

using System;

namespace Operations
{

    class Program
    {
        static void Main()
        {
            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


           Predicate<int> obj3 = delegate (int x)
            {
                if (x == 1)
                    return true;

                for (var i = 2; i < x; i++)
                {
                    if (x % i == 0)
                        return true;
                }

                return false;
            };

            Action<int> obj4 = x => Console.WriteLine($"In MathOperation {x}");

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }
}

Predicate with lambda expression

Lambda expression can also be assigned to a Predicate delegate type as shown below.

using System;

namespace Operations
{

    class Program
    {
        static void Main()
        {
            Func<int, int, int> obj1 = delegate (int x, int y)
            {
                var ans = x;
                for (var i = 1; i < y; i++)
                {
                    ans *= x;
                }

                return ans;
            };


            Func<int, int> obj2 = delegate (int x)
            {
                return x * x;
            };


           Predicate<int> obj3 = x =>
           {
               if (x == 1)
                   return true;

               for (var i = 2; i < x; i++)
               {
                   if (x % i == 0)
                       return true;
               }

               return false;
           };

            Action<int> obj4 = x => Console.WriteLine($"In MathOperation {x}");

            var result = obj1(4, 3);
            Console.WriteLine(result);

            result = obj2(10);
            Console.WriteLine(result);

            obj4(12);
            var bResult = obj3(6);
            Console.WriteLine(bResult ? "Prime Number" : "Not Prime Number");
            Console.ReadLine();
        }
    }
}

Predicate Overview

• Predicate delegate takes one input parameter and Boolean return type.
• Anonymous method and Lambda expression can be assigned to the predicate delegate.

You can test your knowledge by taking an online free quiz on Generic Delegate and Here are Interview questions on generic delegates.

Leave a Reply

Your email address will not be published. Required fields are marked *