As I mentioned about delegate in my earlier blog [https://www.c-sharpcorner.com/article/overview-of-delegate-concept-in-c-sharp/]
Delegate functionality is provided through the System.Delegate Namespace.
Mainly, delegate is used in C# and .NET is for two purposes, which are given below.
	- Callback &
- Event Handling
Now let us see in-depth details about the Action and Func delegates concept in c#
Action delegates: We can say they are predefined delegates that point to any method that takes any number of parameters and returns void.
Code snippet
class SandipClass
{
    // Delegate definition
    delegate void RepoDelegate(string msg);
    // A method that prints a message
    public static void RepoMessage(string msg)
    {
        Console.WriteLine(msg);
    }
    static void Main(string[] args)
    {
        // Creating an instance of the delegate and assigning the method
        RepoDelegate repo = RepoMessage;
        
        // Calling the delegate with a message
        repo("Action Delegate");
        // Waiting for user input before closing
        Console.Read();
    }
}
Output
![Output]()
In the above code snippet, RepoMessage is a method that follows the delegate signature and it takes 1 input parameter and returns nothing(i.e. void).
// Below line of code is used to declare delegate type
delegate void RepoDelegate(string msg);
// Below line of code is used to create a delegate instance
RepoDelegate repo = RepoMessage;
// Below line of code is used to invoke the delegate
repo("Action Delegate");
Func delegates: we can say they are predefined delegates that point to any method that takes any number of parameters and returns any value of any type.
Code snippet
class SandipClass
{
    // Declare delegate type
    delegate int RepoSquareDelegate(int x);
    // A method that calculates the square of a number
    public static int RepoSquare(int x)
    {
        return x * x;
    }
    static void Main(string[] args)
    {
        // Create a delegate instance
        RepoSquareDelegate repo_square = RepoSquare;
        // Invoke the delegate and store the result
        int repo_result = repo_square(10);
        Console.WriteLine("The value of repo_result is :{0}", repo_result);
        // Or, use a Func delegate
        Func<int, int> repo_square1 = RepoSquare;
        // Invoke the Func delegate and store the result
        int repo_result_1 = repo_square1(10);
        Console.WriteLine("The value of repo_result_1 is :{0}", repo_result_1);
        Console.Read();
    }
}
In the above code snippet, RepoSquare is a method that follows a delegate signature and it takes 1 input parameter and returns the value of the type integer.
// Below line of code is used to declare delegate type
delegate int RepoSquareDelegate(int x);
// Below line of code is used to create a delegate instance
RepoSquareDelegate repo_square = RepoSquare;
Func<int, int> repo_square1 = RepoSquare;
// Below line of code is used to invoke the delegate
int repo_result = repo_square(10);
int repo_result_1 = repo_square(10);
Output
The value of repo_result is 100
The value of repo_result_1 is 100