Making delegates and if statements more efficient.

VitzzViperzz

Well-known member
Joined
Jan 16, 2017
Messages
75
Location
United Kingdom
Programming Experience
1-3
Hello,

So I just randomly decided to make a calculator to test what delegates could do. So I thought that I would make a set of delegates under Class Program

C#:
delegate double CalculationProcess(double param1, double param2);
static double Add(double param1, double param2) => param1 + param2;
static double Subtract(double param1, double param2) => param1 - param2;
static double Multiply(double param1, double param2) => param1 * param2;
static double Divide(double param1, double param2) => param2 / param2;

I then got the input and used a few (a lot more than a few) if and else if statements to point the program in the right direction for the correct calculation:

C#:
CalculationProcess process;
            Console.WriteLine("Enter a number: ");
            string userInput1 = Console.ReadLine();
            Console.WriteLine("Enter a second number: ");
            string userInput2 = Console.ReadLine();
            double param1 = Convert.ToDouble(userInput1);
            double param2 = Convert.ToDouble(userInput2);


            Console.WriteLine(" Enter A for add\n Enter S for subtract\n Enter M for Multiply\n Enter D for Divide");
            string userDecision = Console.ReadLine();
            if (userDecision == "A")
            {
                process = new CalculationProcess(Add);
            }
            else if (userDecision == "S")
            {
                process = new CalculationProcess(Subtract);
            }
            else if (userDecision == "M")
            {
                process = new CalculationProcess(Multiply);
            }
            else
            {
                process = new CalculationProcess(Divide);
            }


            
            Console.WriteLine($"The result is: {process(param1, param2)}");
            Console.ReadKey();

But my question is, how can I make the section with the if statements more efficient. because this seems like a pain to do for larger applications.

Also, any suggestions on anything other than Delegates to achieve the same results? More method based?

Thanks :star:
 
So I thought that I would make a set of delegates under Class Program

C#:
delegate double CalculationProcess(double param1, double param2);
static double Add(double param1, double param2) => param1 + param2;
static double Subtract(double param1, double param2) => param1 - param2;
static double Multiply(double param1, double param2) => param1 * param2;
static double Divide(double param1, double param2) => param2 / param2;
That's not a set of delegates. That is one delegate and four methods. I believe that I went through this with just Multiply and Divide in another thread of yours. CalculationProcess is a delegate type that can refer to a method that has two 'double' parameters and a return type of 'double'. Add, Subtract, Multiply and Divide are all methods with that signature and can thus all be referred to by a CalculationProcess delegate.
C#:
CalculationProcess process;
            Console.WriteLine("Enter a number: ");
            string userInput1 = Console.ReadLine();
            Console.WriteLine("Enter a second number: ");
            string userInput2 = Console.ReadLine();
            double param1 = Convert.ToDouble(userInput1);
            double param2 = Convert.ToDouble(userInput2);


            Console.WriteLine(" Enter A for add\n Enter S for subtract\n Enter M for Multiply\n Enter D for Divide");
            string userDecision = Console.ReadLine();
            if (userDecision == "A")
            {
                process = new CalculationProcess(Add);
            }
            else if (userDecision == "S")
            {
                process = new CalculationProcess(Subtract);
            }
            else if (userDecision == "M")
            {
                process = new CalculationProcess(Multiply);
            }
            else
            {
                process = new CalculationProcess(Divide);
            }


            
            Console.WriteLine($"The result is: {process(param1, param2)}");
            Console.ReadKey();

But my question is, how can I make the section with the if statements more efficient. because this seems like a pain to do for larger applications.
In a situation like this, where you have to determine which of multiple inputs the user provided, there's only so much you can do. The immediately obvious option is to use a 'switch' statement rather than 'if...else if':
switch (userDecision)
{
    case "A":
        process = new CalculationProcess(Add);
        break;
    case "S":
        process = new CalculationProcess(Subtract);
        break;
    case "M":
        process = new CalculationProcess(Multiply);
        break;
    case "D":
        process = new CalculationProcess(Divide);
        break;
    default:
        // Notify user of invalid input.
        break;
}

Note that I have also not simply assumed that the input was "D" if it wasn't "A", "S" or "M".

Another option could be to use a Dictionary:
var calculationProcesses = new Dictionary<string, CalculationProcess>
                            {
                                {"A", Add},
                                {"S", Subtract},
                                {"M", Multiply},
                                {"D", Divide}
                            };
CalculationProcess process;

if (calculationProcesses.TryGetValue(Console.ReadLine(), out process))
{
    // Invoke process here.
}
else
{
    // Inform user of invalid input.
}

Note that you don't have to use the CalculationProcess constructor explicitly. Because a CalculationProcess delegate is expected, you can just use a method group with a compatible signature and the compiler infers that you want to create a CalculationProcess delegate.
Also, any suggestions on anything other than Delegates to achieve the same results? More method based?
In this situation, the delegate provides the ability to store the method to execute in a variable and then execute it in one place, regardless of which method it is. Without the delegate, you couldn't use the Dictionary option because you can't store methods without delegates but you could use the 'switch' option and, rather than create a delegate in each case and invoke that later, just call the appropriate method in each case and store the result in a single variable for later use:
switch (userDecision)
{
    case "A":
        result = Add(param1, param2);
        break;
    case "S":
        result = Subtract(param1, param2);
        break;
    case "M":
        result = Multiply(param1, param2);
        break;
    case "D":
        result = Divide(param1, param2);
        break;
    default:
        // Notify user of invalid input.
        break;
}
 
That's not a set of delegates. That is one delegate and four methods. I believe that I went through this with just Multiply and Divide in another thread of yours. CalculationProcess is a delegate type that can refer to a method that has two 'double' parameters and a return type of 'double'. Add, Subtract, Multiply and Divide are all methods with that signature and can thus all be referred to by a CalculationProcess delegate.

In a situation like this, where you have to determine which of multiple inputs the user provided, there's only so much you can do. The immediately obvious option is to use a 'switch' statement rather than 'if...else if':
switch (userDecision)
{
case "A":
process = new CalculationProcess(Add);
break;
case "S":
process = new CalculationProcess(Subtract);
break;
case "M":
process = new CalculationProcess(Multiply);
break;
case "D":
process = new CalculationProcess(Divide);
break;
default:
// Notify user of invalid input.
break;
}

Note that I have also not simply assumed that the input was "D" if it wasn't "A", "S" or "M".

Another option could be to use a Dictionary:
var calculationProcesses = new Dictionary<string, CalculationProcess>
{
{"A", Add},
{"S", Subtract},
{"M", Multiply},
{"D", Divide}
};
CalculationProcess process;

if (calculationProcesses.TryGetValue(Console.ReadLine(), out process))
{
// Invoke process here.
}
else
{
// Inform user of invalid input.
}

Note that you don't have to use the CalculationProcess constructor explicitly. Because a CalculationProcess delegate is expected, you can just use a method group with a compatible signature and the compiler infers that you want to create a CalculationProcess delegate.

In this situation, the delegate provides the ability to store the method to execute in a variable and then execute it in one place, regardless of which method it is. Without the delegate, you couldn't use the Dictionary option because you can't store methods without delegates but you could use the 'switch' option and, rather than create a delegate in each case and invoke that later, just call the appropriate method in each case and store the result in a single variable for later use:
switch (userDecision)
{
case "A":
result = Add(param1, param2);
break;
case "S":
result = Subtract(param1, param2);
break;
case "M":
result = Multiply(param1, param2);
break;
case "D":
result = Divide(param1, param2);
break;
default:
// Notify user of invalid input.
break;
}


Okay, I get it now. The last bit with the input handling was actually very smart - I never considered that. :)

Thank you for the reply.
 
Back
Top Bottom