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.WriteLines 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);