bmakl
bmakl

Reputation: 17

Am I using C# delegates in a useful way?

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

Answers (3)

NetMage
NetMage

Reputation: 26917

Once way you could use delegates 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

Christopher
Christopher

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

gabriel.hayes
gabriel.hayes

Reputation: 2313

I've created a Repl demonstrating a Worker pattern utilizing basic delegates (Actions, 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

Related Questions