Reputation: 17
I am doing a simple exercise using delegates in C#. The basic premise is that it simply performs calculations like addition and subtraction.
public class Calculator
{
public static int Add(int num1, int num2)
{
return num1 + num2;
}
public static int Multiply(int num1, int num2)
{
return num1 * num2;
}
public static int Subtract(int num1, int num2)
{
return num1 - num2;
}
}
And I have created a delegate that will call these functions in another class.
public delegate int CalculatorDelegate(int num1, int num2);
The implementation class looks like this:
public class Calculation
{
public int PerformCalculation(int choice, int number1, int number2)
{
CalculatorDelegate cd;
if (choice == 1)
{
cd = Calculator.Add;
return cd(number1, number2);
}
else if (choice == 2)
{
cd = Calculator.Subtract;
return cd(number1, number2);
}
else if (choice == 3)
{
cd = Calculator.Multiply;
return cd(number1, number2);
}
else
{
cd = Calculator.Add;
return cd(number1, number2);
}
}
}
What's confusing me about delegates is why not just do the following instead?
if (choice == 1)
{
return Calculator.Add(number1,number2);
}
I think my confusion is surrounding the fact that if these methods are already static, what's the point of even making a delegate to them. I can simply just call them as static methods. If I try to make the methods non-static, then I cant have my delegate point to them in this other class, without creating some object of the other class.
I am all turned around on this example and what it even accomplishes and maybe someone can provide me some insight as to if I'm even using this remotely close to how it should be?
Upvotes: 0
Views: 500
Reputation: 26917
Once way you could use delegate
s in your example is to have a mapping from choice to CalculatorDelegate
, then you just lookup the desired calculation and perform it:
static List<CalculatorDelegate> ChoiceMap = new List<CalculatorDelegate> { Calculator.Add, Calculator.Subtract, Calculator.Multiply };
public class Calculation {
public int PerformCalculation(int choice, int number1, int number2) =>
ChoiceMap[choice-1](number1, number2);
}
But since delegates are converted automatically from lambdas (CalculatorDelegate
is essentially Func<int,int,int>
), you no longer need the Calculator
class:
static List<CalculatorDelegate> ChoiceMap = new List<CalculatorDelegate> {
(n1, n2) => n1+n2,
(n1, n2) => n1-n2,
(n1, n2) => n1*n2
};
Note that the types of n1
and n2
in each lambda are inferred from CalculatorDelegate
. Now adding new operations to PerformCalculation
is simply a matter of adding a new lambda to the ChoiceMap
.
Hopefully you can see how you could use a more complicated type for ChoiceMap
, such as a Dictionary<string,Func<int,int,int>>
where each key is a string representing an operator (e.g. "+"
) and the value is the operation to perform, which makes mapping to a simple calculator easy.
I use a similar Dictionary
in a command line switch management helper, where each entry has the command name, the number of arguments, the delegate (method) to call (which may be a lambda when simple enough), the command grouping and some help text, where help output is generated automatically from the same Dictionary
.
Upvotes: 0
Reputation: 9804
Delegates are types. Types that take a reference to a function, rather then some other value.
Delegates are there to hand functions as a argument to another function. Or to be used as the type for a generic class - mostly collections in practice. There are one of the many replacements for naked pointers that had to be invented, so .NET could shield you from having to handle naked pointers.
However they are also a case where the repalcement turned out to be better by a fair margin. For example, it is very possible to replace a switch/case with a Dictionary<caseLabel, delegateThatTakesAArgument>
. If I gave you a int
pointer in Native C++. you could not tell if this was a single variable I hand in by reference, the start of a array or a Function that returns int. With all those Pointer replacements, you know.
For this specific case, those functions themself are overkill. Delegates are even more overkill. That "PerformCalculation" function, sounds like it should be the User Input Interpreation part of a Console Application, not a function.
However there are not a lot of good, unambigious examples for Delegate use. So for learning it propably works okay. It is often a case where you have to make a judgement call between a switch/case with hardcoded operation and Delegates.
However Events are one of the rare clear cut case for Delegates I can think off. If you learn them for nothing else, learn them for Events.
Upvotes: 4
Reputation: 2313
I've created a Repl demonstrating a Worker pattern utilizing basic delegates (Action
s, a type of delegate built into the standard library that takes no parameters and returns nothing).
You can check it out here.
ETA: The most common use-case for delegates is asynchronous/threaded programming.
Threads require delegates to run as they do not know the code to be run beforehand, they simply carry it as a parameter into the newly created thread of execution, it would otherwise be impossible to create threads (well, without having lower-level access than C# provides)
Check out the MSDN docs on the Threading API
Similarly, in asynchronous programming, you will generally need a callback (which would be a delegate in C#) in order to defer execution of the code until pre-existing conditions are met. (A runloop for example, a common alternative to threading which uses a single thread to execute multiple tasks "concurrently" step-by-step)
Upvotes: 0