.NET Delegates
.NET Delegates
Introduction to Actions
Overview
Because the concepts of delegates are very important, valuable, and useful in programming, the .NET Framework provides a special delegate, that is, pre-built. This delegate is named Action. The Action delegate is provided in many (overloaded) versions so that you can find a syntax that suits any need. This means that in many cases, instead of creating your delegate(s) from scratch, you can use the Action delegate instead.
A Simple Action
As we saw in our introduction, the simplest delegate is a method that doesn't use any parameter. Here is the example:
using System; delegate void Observation(); public class Exercise { public static int Main() { Observation quote = new Observation(HoldConference); quote(); return 0; } private static void HoldConference() { Console.WriteLine("There are known knowns. These are things we know that we know.\n" + "There are known unknowns. That is to say, there are things that we know we don't know.\n" + "But there are also unknown unknowns. There are things we don't know we don't know. - Donald Rumsfeld -"); } }
This would produce:
There are known knowns. These are things we know that we know. There are known unknowns. That is to say, there are things that we know we don't know. But there are also unknown unknowns. There are things we don't know we don't know. - Donald Rumsfeld - Press any key to continue . . .
To support delegates that don't use any parameters, the .NET Framework provides the following version of the Action delegate:
public delegate void Action()
Based on this version of the Action delegate, you don't have to first create a delegate. In the section where you declare a variable for the delegate, use Action. This can be done as follows:
using System; public class Exercise { public static int Main() { Action quote = new Action(HoldConference); quote(); return 0; } private static void HoldConference() { Console.WriteLine("There are known knowns. These are things we know that we know.\n" + "There are known unknowns. That is to say, there are things that we know we don't know.\n" + "But there are also unknown unknowns. There are things we don't know we don't know. - Donald Rumsfeld -"); } }
You don't need to use the new operator to initialize the variable. This means that you can omit calling Action() as a constructor. Therefore, the above code can be written as follows:
using System;
public class Exercise
{
public static int Main()
{
Action quote = HoldConference;
quote();
return 0;
}
private static void HoldConference()
{
Console.WriteLine("There are known knowns. These are things we know that we know.\n" +
"There are known unknowns. That is to say, there are things that we know we don't know.\n" +
"But there are also unknown unknowns. There are things we don't know we don't know. - Donald Rumsfeld -");
}
}
Actions and Anonymous Methods
Action delegates support anonymous methods. The anonymous delegate is created in the same way done for regular delegates. That is, initialize the Action variable with the delegate keyword, the parentheses, and the body of the method in curly brackets. Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Action elementaryAlgebra = delegate ()
{
Random rndNumber = new Random();
int number1 = rndNumber.Next(0, 20);
int number2 = rndNumber.Next(0, 20);
int total = number1 + number2;
Console.WriteLine(number1 + " + " + number2 + " = " + total);
};
elementaryAlgebra();
return 0;
}
}
Here is an example of running the program:
18 + 18 = 36 Press any key to continue . . .
Actions and Lambda Expressions
Like regular delegates, actions support lambda expressions. To apply a lambda expression to an action delegate, initialize the Action variable with empty parentheses, the => operator, and the body of the method. Here is an example:
using System; public class Exercise { public static int Main() { Action elementaryAlgebra = () => { Random rndNumber = new Random(); int number1 = rndNumber.Next(0, 200); int number2 = rndNumber.Next(0, 200); int total = number1 + number2; Console.WriteLine(number1 + " + " + number2 + " = " + total); }; elementaryAlgebra(); return 0; } }
Here is an example of running the program:
168 + 164 = 332 Press any key to continue . . .
A Delegate With a Parameter
We saw that a delegate can use a parameter. In fact, the Action delegate is created as generic. To support the ability to apply a parameter to a delegate, the .NET Framework provides an Action delegate that uses the following syntax:
public delegate void Action<in T>(T obj)
The parameter can be any type, such as a primitive type or a string. When declaring the variable, to indicate that the delegate is using a parameter, use Action<>. Include the parameter type between < and >. Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Action<string> quote = new Action<string>(Create);
return 0;
}
public static void Create(string say)
{
Console.WriteLine(say);
}
}
You can omit the second Action<string>. Once again, when calling the method, pass an appropriate argument. Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Action<string> quote = Create;
quote("Ces dances à la gloire de la fornication.");
return 0;
}
public static void Create(string say)
{
Console.WriteLine(say);
}
}
This would produce:
Ces dances à la gloire de la fornication. Press any key to continue . . .
An Action Delegate With Many Parameters
The Action delegate can use different numbers and types of parameters. To support this, the .NET Framework provides 17 versions of the Action delegate ranging from one that doesn't use any parameter to one that takes 16 arguments. To use one of them, declare a variable of type Action<>. Between < and >, enter the types separated by commas. Initialize the variable with a method that use the same number or ordinal types of parameters.
An Action Delegate as a Type
Returning an Action
You can create a method that returns an Action delegate. As seen for formal delegates, when creating the method, set its return type as Action. In the body of the method, do what you want. Before the end of the method, return an object of the Action type. One solution is to declare a variable of Action type and initialize it appropriately. before calling the method, you can declare a variable and assign the Action method to it. Then call that last variable as if it were a method. Here is an example:
using System; public class Exercise { public static int Main() { Action operation = Doubler(); operation(); return 0; } private static Action Doubler() { Action times = new Action(Multiplication); return times; } private static void Multiplication() { Random rndNumber = new Random(); int number1 = rndNumber.Next(0, 100); int number2 = rndNumber.Next(0, 100); int total = number1 * number2; Console.WriteLine(number1 + " * " + number2 + " = " + total); } }
Here is an example of running the program:
63 * 68 = 4284 Press any key to continue . . .
In the same way, a method can return a collection or an array of Action values.
An Action as Parameter
To create a method that uses a parameter of type Action, precede that name of the parameter with Action. Here is an example:
public class Exercise
{
public void Create(Action speech)
{
}
}
In the same way, as opposed to passing it by itself, an Action delegate can be passed as argument along with other (types of) parmeters. In the body of the method, ignore or use the Action parameter. Probably the simplest way to use it is to call it as a method. Here is an example:
public class Exercise
{
public void Create(Action speech)
{
speech();
}
}
When calling the method, you can pass the name of a method that uses the same syntax as the type of Action that was passed as parameter (remember that the .NET Framework provides various syntaxes for actions). Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Create(Hold);
return 0;
}
private static void Hold()
{
Console.WriteLine("People who live in glass houses should not throw stones");
}
private static void Create(Action speech)
{
speech();
}
}
.NET Function Delegates
Introduction
An Action is a delegate for a method that doesn't produce a value. A function is an action that produces or returns a value. At a minimum, a function doesn't use any parameter.
Although you can create your own function delegates , to provide you a faster technique, the .NET Framework provides a special delegate named Func. It uses a generic format as in Func<>.
Web Project: School UniCorp We are starting a web project for a company named School UniCorp. This is a fictitious company that makes and sells school uniforms. As we start, the company makes shirts and pants and sells them at fixed prices. As we move on in our lessons, we will see how the business changes (we will consider shirts and pants sizes, and different prices). |
A Simple Function Delegate
Consider the following code:
using System; delegate double Evaluation(); public class Exercise { public static int Main() { Evaluation eval = new Evaluation(Calculate); Console.WriteLine("Weekly Salary = {0}", eval().ToString("F")); return 0; } private static double Calculate() { double hSalary = 25.75; double tWorked = 38.50; double wSalary = hSalary * tWorked; return wSalary; } }
This would produce:
Weekly Salary = 991.38 Press any key to continue . . .
A simple function is one that doesn't use any parameter but returns a value. To support it, the .NET Framework provides a Func<> delegate that uses the following syntax:
public delegate TResult Func<out TResult>()
The out TResult expression indicates that the delegate returns a value as TResult. When creating the method for the delegate, you must indicate the desired return value. To associate the method to the delegate, declare a Func<> variable. Between < and >, include the same return type as the method. Initialize the variable with the name of the method. You can then call the variable as if it were a method. This can be done as follows:
using System;
public class Exercise
{
public static int Main()
{
Func<double> eval = new Func<double>(Calculate);
Console.WriteLine("Weekly Salary = {0}", eval().ToString("F"));
return 0;
}
private static double Calculate()
{
Random rndSelection = new Random();
double[] salaries = { 29.73, 18.52, 37.59, 16.44, 25.75 };
double[] timesWorked = { 40.00, 42.50, 37.50, 38.50, 41.00 };
double wSalary = salaries[rndSelection.Next(1, 5)] * timesWorked[rndSelection.Next(1, 5)];
return wSalary;
}
}
Here is an example of running the program:
Weekly Salary = 713.02 Press any key to continue . . .
In the above code, we used the new operator to initialize the variable. You can omit it. Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Func<double> eval = Calculate;
Console.WriteLine("Weekly Salary = {0}", eval().ToString("F"));
return 0;
}
private static double Calculate()
{
Random rndSelection = new Random();
double[] salaries = { 29.73, 18.52, 37.59, 16.44, 25.75 };
double[] timesWorked = { 40.00, 42.50, 37.50, 38.50, 41.00 };
double wSalary = salaries[rndSelection.Next(1, 5)] * timesWorked[rndSelection.Next(1, 5)];
return wSalary;
}
}
Here is an example of running the program:
Weekly Salary = 1447.22 Press any key to continue . . .
A Simple Anonymous Function Delegate
You can use the delegate keyword to create an anonymous function delegate. The technique is the same we have used so far. Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Func<double> eval = delegate ()
{
double hSalary = 25.75;
double tWorked = 38.50;
double wSalary = hSalary * tWorked;
return wSalary;
};
Console.WriteLine("Weekly Salary = {0}", eval().ToString("F"));
return 0;
}
}
This would produce:
Weekly Salary = 991.38 Press any key to continue . . .
A Simple Lambda Expression
A function delegate that uses a parameter supports lambda expressions. To implement it, remove the delegate keyword and add the => operator after the parentheses. Here is an example:
using System;
public class Exercise
{
public static int Main()
{
Func<double> eval = () =>
{
Random rndSelection = new Random();
double[] salaries = { 29.73, 18.52, 37.59, 16.44, 25.75 };
double[] timesWorked = { 40.00, 42.50, 37.50, 38.50, 41.00 };
double wSalary = salaries[rndSelection.Next(1, 5)] * timesWorked[rndSelection.Next(1, 5)];
return wSalary;
};
Console.WriteLine("Weekly Salary = {0}", eval().ToString("F"));
return 0;
}
}
Here is an example of running the program:
Weekly Salary = 1409.63 Press any key to continue . . .
A Function Delegate with a Parameter
To support function delegates that use one parameter, the .NET Framework provides a delegate that uses the following syntax:
public delegate TResult Func<in T, out TResult>(T arg);
This syntax is for a function that takes one argument (and of course returns a value). Here is an example of such a function (and how to access it):
using System;
public delegate double Operation(double a);
public class Exercise
{
private static readonly double hourlySalary = 12.75;
public static int Main()
{
Operation oper = Multiply;
double dailySalary = EvaluateSalary(oper);
Console.WriteLine("Daily Salary = {0}", dailySalary.ToString("F"));
return 0;
}
private static double Multiply(double timeWorked)
{
if (timeWorked <= 8)
{
return hourlySalary * timeWorked;
}
else
{
double regularPay = 8.00 * hourlySalary;
double overtimePay = (timeWorked - 8.00) * hourlySalary * 1.50;
return regularPay + overtimePay;
}
}
private static double EvaluateSalary(Operation calc)
{
return calc(hourlySalary);
}
}
This would produce:
Daily Salary = 192.84 Press any key to continue . . .
To simply your code, you can use a Func delegate. Instead of this:
using System; delegate double Operation(double a); public class Exercise { private static readonly double hourlySalary = 12.75; public static int Main() { double dailySalary = EvaluateSalary(timeWorked => { if (timeWorked <= 8) { return hourlySalary * timeWorked; } else { double regularPay = 8.00 * hourlySalary; double overtimePay = (timeWorked - 8.00) * hourlySalary * 1.50; return regularPay + overtimePay; } }); Console.WriteLine("Daily Salary = {0}", dailySalary.ToString("F")); return 0; } private static double EvaluateSalary(Operation calc) { return calc(hourlySalary); } }
You can use this:
using System;
public class Exercise
{
private static readonly double hourlySalary = 22.75;
public static int Main()
{
Func<double, double> Calculate = new Func<double, double>(timeWorked =>
{
if (timeWorked <= 8)
{
return hourlySalary * timeWorked;
}
else
{
double regularPay = 8.00 * hourlySalary;
double overtimePay = (timeWorked - 8.00) * hourlySalary * 1.50;
return regularPay + overtimePay;
}
});
double dailySalary = Calculate(12.00);
Console.WriteLine("Daily Salary = {0}", dailySalary.ToString("F"));
return 0;
}
}
This would produce:
Daily Salary = 318.50 Press any key to continue . . .
Because the above function included many lines of code, we created a body for it and delimited it with curly brackets. If a function includes a single line of code, it doesn't need a body. Here is an example:
using System;
public class Exercise
{
private static readonly double hourlySalary = 17.36;
public static int Main()
{
Func<double, double> Calculate = timeWorked => hourlySalary * timeWorked;
double dailySalary = Calculate(12.00);
Console.WriteLine("Daily Salary = {0}", dailySalary.ToString("F"));
return 0;
}
}
This would produce:
Daily Salary = 208.32 Press any key to continue . . .
A Function Delegate as Type
Returning a Function Delegate
A function delegate is a type, like a value type or a class. As such, you can create a method that returns a function. To do this, specify Func<> as the return type. The parameter type can be a value type. Here is an example:
public class Exercise
{
public Func<double> Calculate()
{
}
}
Do whatever you want in the method but before it ends, return a value of type Func<>. Here is an example:
public class Exercise
{
public Func<int> Calculate()
{
Func<int> result = Addition;
return result;
}
private int Addition()
{
Random rndNumber = new Random();
int number1 = rndNumber.Next(0, 420);
int number2 = rndNumber.Next(0, 620);
int total = number1 + number2;
return total;
}
}
You can also just return the name of the method that returns the function delegate. Here is an example:
public class Exercise
{
public Func<int> Calculate()
{
return Addition;
}
private int Addition()
{
Random rndNumber = new Random();
int number1 = rndNumber.Next(0, 20);
int number2 = rndNumber.Next(0, 20);
int total = number1 + number2;
return total;
}
}
When calling the method, you can assign the call to a variable of type Func<>. Here is an example:
using System;
public class Exercise
{
private static Func<int> Calculate()
{
Func<int> result = Addition;
return result;
}
private static int Addition()
{
Random rndNumber = new Random();
int number1 = rndNumber.Next(0, 420);
int number2 = rndNumber.Next(0, 620);
int total = number1 + number2;
return total;
}
public static int Main()
{
Func<int> eval = Calculate();
Console.WriteLine("Result: " + eval());
return 0;
}
}
This would produce:
Result: 818 Press any key to continue . . .
A Function Delegate as Parameter With One Parameter
We already know that you can pass a function as argument if you use a delegate. Here is an example:
using System;
delegate double Operation(double a);
public class Exercise
{
private static readonly double value = 148.86;
private static double Multiply(double side)
{
return side * side;
}
private static double Calculate(Operation oper)
{
return oper(value);
}
public static int Main()
{
double area = Calculate(Multiply);
Console.WriteLine("Area of Cube: " + area);
return 0;
}
}
This would produce:
Area of Cube: 22159.2996 Press any key to continue . . .
When creating the method, instead of your own function, you can use Func<>. Here is an example for a function that takes one argument:
using System;
public class Exercise
{
private static double GatValue()
{
Console.Write("Type the side value of the cube: ");
return double.Parse(Console.ReadLine());
}
private static double Multiply(double side)
{
return side * side;
}
private static double Calculate(Func<double, double> oper)
{
return oper(GatValue());
}
public static int Main()
{
double area = Calculate(Multiply);
Console.WriteLine("Area of Cube: " + area);
return 0;
}
}
Here is an example of running the program:
Type the side value of the cube: 249.73 Area of Cube: 62365.0729 Press any key to continue . . .
Calling a One-Parameter Function Locally
When calling the method, instead of first creating a method that would be passed as argument, you can define the method directly where it is needed. Here is an example:
using System;
public class Exercise
{
private static double GatValue()
{
Console.Write("Type the side value of the cube: ");
return double.Parse(Console.ReadLine());
}
private static double Calculate(Func<double, double> oper)
{
return oper(GatValue()) * 6.00;
}
public static int Main()
{
double area = Calculate((double side) =>
{
return side * side;
});
Console.WriteLine("Area of Cube: " + area);
return 0;
}
}
Here is an example of running the program:
Type the side value of the cube: 337.96 Area of Cube: 685301.7696 Press any key to continue . . .
Remember that you can omit the data type(s) of the parameter(s). Also remember that if the method is using one parameter, the parameter doesn't need parentheses. And if the method contains a single statement, it doesn't need a body. Here is an example:
using System;
public class Exercise
{
private static double GatValue()
{
Console.Write("Type the side value of the cube: ");
return double.Parse(Console.ReadLine());
}
private static double Calculate(Func<double, double> oper)
{
return oper(GatValue());
}
public static int Main()
{
double area = Calculate(side => side * side);
Console.WriteLine("Area of Cube: " + area);
return 0;
}
}
Here is an example of running the program:
Type the side value of the cube: 705.58 Area of Cube: 497843.1364 Press any key to continue . . .
Processing a Function in its Method
When creating a method that will be used to access function delegate, you can involve that function in an operation with constants or external values of your choice. After doing this, when calling the method, you can just pass a parameter and not process it again.
Applying Value Processing to a Function Delegate
Obviously it is not always enough to just call a function delegate and pass an argument to it. Many times, you want the function delegate to perform some operations on its argument(s) and produce a result as complex as you want. One way you can do this is to include one or more conditional statements in the method. In fact, you can even call other methods or involve other libraries in the method that calls the function delegate.
A Function Delegate with Two Parameters
Depending on your project, you may need a function that uses two parameters. To support this concept for function delegates, the .NET Framework provides the following version of the Func<> delegate:
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
This generic delegate uses three parameter types. The last parameter type,TResult, is the return type of the function. The first two types represent the data types of the parameters. In a simple version, they can be value types (number, character, Boolean) or a string. They can be the same or different types.
As seen with function delegates of one parameter, you can create a method that takes one parameter, you can create a method that takes a function of two parameters and, in the method, simply call the function and pass two arguments. you can use arguments you also pass to the method. Here is an example:
public double EvaluateSubTotal(Func<int, double, double> calc, int qty, double amount) { return calc(qty, amount); }
In this case, when calling the method, in the placeholder of the function passed as parameter, type parentheses and in which you must include two arguments separated by a comma. Outside the parentheses, type => followed by the desired operation for the arguments. Here is an example:
double subTotalShirtsSmall = hc.EvaluateSubTotal((q, a) => q * a,
iQuantityShirtsSmall, dUnitPriceShirtsSmall);
Alternatively, you can perform the operation in the method that uses the function delegate. Here is an example:
public double EvaluateSubTotal(Func<int, double, double> calc, int qty, double amount)
{
return qty * amount;
}
Alternatively, you can define a function delegate where it is needed, then call it. Here is an example
double subTotal = 2425.75;
int shippingAndHanling = 36.75;
Func<double, double, double> Plus = (a, b) => a + b;
double invoiceTotal = Plus(subTotal, shippingAndHanling);
A .NET Function Delegate With Many Parameters
To support function delegates that can use various numbers and types of parameters, the .NET Framework provides 17 versions of the Func delegates. One version is for a function that uses no parameter. The other versions are for functions that take 1 to 16 arguments. The syntaxes of the function delegates are:
public delegate TResult Func<out TResult>(); public delegate TResult Func<in T, out TResult>(T arg); public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2); public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3); public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>( T1 arg1, T2 arg2, T3 arg3, T4 arg4); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, out TResult>( T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
As we saw already, for the first syntax, TResult is the only factor and it represents the return value. For the other syntaxes, the last parameter, TResult, is the return value. This means that, when declaring the Func<> variable, between < and >, start with the type(s) of the parameter(s) and end with the return type.
Everyone of these functions can be passed as argument or returned from a method.
|
||
Previous | Copyright © 2008-2019, FunctionX | Next |
|