There are a bunch of things that could be touched upon, but given you're a beginner, I would like to show a couple things. One is a language-technical thing, while the other is an overall design thing. Let's start with the second, which is called in programming circles as separation of concerns. What is a concern? File IO, calculations, interacting with the user, accessing a web service, etc. In your code's case, the calculations and interacting with the user are combined together in the local methods, so let's use a quick little language feature known as return types to let the calculations do ONLY calculations:
static int Plus(int a, int b)
{
int c = a + b;
return c;
}
static int Minus(int a, int b)
{
int c = a - b;
return c;
}
static int Times(int a, int b)
{
int c = a * b;
return c;
}
static int Divide(int a, int b)
{
int c = a / b;
return c;
}
now this code is reusable in other domains in which you are not interacting with the user via Console.WriteLine
. Now because of that, calling code needs to be adjusted somewhat:
Console.WriteLine("Which operation? (+, -, *, /)");
string op = Console.ReadLine() ??"";
int c;
if (op == "+")
{
c = Plus(a, b);
Console.WriteLine(a + "+" + b + " = " + c);
}
else if (op == "-")
{
c = Minus(a, b);
Console.WriteLine(a + "-" + b + " = " + c);
}
else if (op == "*")
{
c = Times(a, b);
Console.WriteLine(a + "+" + b + " = " + c);
}
else if (op == "/")
{
c = Divide(a, b);
Console.WriteLine(a + "/" + b + " = " + c);
}
else
{
Console.WriteLine("Incorrect operation entry!");
}
This is keeping your user interaction in one place. However, there seems to be quite a bit of repeated code here, and there's a principle called DRY (Don't Repeat Yourself) we can implement using a C# feature known as a switch statement. Here's the adjustment now:
Console.WriteLine("Which operation? (+, -, *, /)");
string op = Console.ReadLine() ??"";
int c;
switch (op)
{
case "+":
c = Plus(a, b);
break;
case "-":
c = Minus(a, b);
break;
case "*":
c = Times(a, b);
break;
case "/":
c = Divide(a, b);
break;
default:
Console.WriteLine("Incorrect operation entry!");
return;
}
Console.WriteLine(a + op + b + " = " + c);
This took the four ever so slightly different Console.WriteLine
s and combined them into one (since we had op
in hand).
Now there are many other ways to refine the code, taking advantage of more object-oriented principles, but I think these two items make your entry-level application tight.
BONUS (ETA 2024-Dec-02) - here's a more object-oriented solution using a base class and subclasses if you feel you want to further separate your logic into classes and subclasses (C#12 syntax, I believe):
Console.WriteLine("Enter the first number: ");
int a = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Enter the second number: ");
int b = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Which operation? (+, -, *, /)");
string op = Console.ReadLine() ?? string.Empty;
object? operation = op switch
{
"+" => new Plus(a, b),
"-" => new Minus(a, b),
"*" => new Times(a, b),
"/" => new Divide(a, b),
_ => null
};
Console.WriteLine(operation ?? "Incorrect operation entry!");
public abstract class Operation(int a, int b, string op, Func<int, int, int> operation)
{
private readonly string _op = !string.IsNullOrWhiteSpace(op) ? op : throw new ArgumentNullException(nameof(op));
private readonly Func<int, int, int> _operation = operation ?? throw new ArgumentNullException(nameof(operation));
public override string ToString() => $"{a}{_op}{b} = {_operation(a, b)}";
}
public sealed class Plus(int a, int b) : Operation(a, b, "+", (ay, be) => ay + be);
public sealed class Minus(int a, int b) : Operation(a, b, "-", (ay, be) => ay - be);
public sealed class Times(int a, int b) : Operation(a, b, "*", (ay, be) => ay * be);
public sealed class Divide(int a, int b) : Operation(a, b, "/", (ay, be) => ay / be);