基于Stack实现带撤销功能的简易C#计算器代码问题求助
Hey there! Let's walk through fixing your calculator with undo functionality—since you're new to using Stack, I'll break down each issue clearly so you understand what's going wrong and how to get it working properly.
First, let's list out the key problems in your code:
- Uninitialized Stack: You declared the
resultstack but never created an instance of it. This will throw a null reference error as soon as you try to push/pop values. - Broken Undo Logic:
result.DefaultIfEmpty()isn't the right way to check if the stack is empty (it returns a sequence with a default value if empty, not a boolean).- You're popping twice, which removes both the current result and the previous one—this will erase valid history.
- Non-functional Main Method:
- C# requires the entry point to be
static void Main(string[] args), notint main(). - You never instantiated your
Calculatorclass or read user input intoline. - The expression parsing section doesn't actually split the user's input into numbers and an operator, so variables
a,b, andcare unassigned.
- C# requires the entry point to be
- Flawed Clear Method: Again,
result.DefaultIfEmpty()is used incorrectly here, and looping to pop each element is unnecessary (Stack has a built-inClear()method). - Minor Style/Access Issues: Methods and fields don't follow C# naming conventions, and some methods have unclear access modifiers.
Here's the fixed, working version of your code:
using System; using System.Collections.Generic; class Calculator { // Use private fields with underscore prefix (C# convention) private Stack<double> _calculationHistory; public double CurrentTotal { get; private set; } // Constructor to initialize our stack and starting total public Calculator() { _calculationHistory = new Stack<double>(); CurrentTotal = 0; } // Renamed methods to follow PascalCase convention public void Add(double a, double b) { CurrentTotal = a + b; Console.WriteLine("Sum: {0}", CurrentTotal); _calculationHistory.Push(CurrentTotal); } public void Subtract(double a, double b) { CurrentTotal = a - b; Console.WriteLine("Difference: {0}", CurrentTotal); _calculationHistory.Push(CurrentTotal); } public void Multiply(double a, double b) { CurrentTotal = a * b; Console.WriteLine("Product: {0}", CurrentTotal); _calculationHistory.Push(CurrentTotal); } public void Divide(double a, double b) { if (b != 0) { CurrentTotal = a / b; Console.WriteLine("Quotient: {0}", CurrentTotal); _calculationHistory.Push(CurrentTotal); } else { Console.WriteLine("Error: Cannot divide by 0"); } } public void Undo() { if (_calculationHistory.Count == 0) { Console.WriteLine("UNDO IS NOT AVAILABLE"); return; } // Pop the current result to remove it from history _calculationHistory.Pop(); // Set total to the last valid result (or 0 if history is empty) CurrentTotal = _calculationHistory.Count > 0 ? _calculationHistory.Peek() : 0; Console.WriteLine("Running total: {0}", CurrentTotal); } public void Clear() { _calculationHistory.Clear(); // Use built-in Clear method for efficiency CurrentTotal = 0; Console.WriteLine("Running total: {0}", CurrentTotal); } // Helper method to parse user's expression input private bool TryParseExpression(string input, out double a, out double b, out char op) { a = 0; b = 0; op = '\0'; // Find the operator in the input string char[] operators = { '+', '-', '*', '/' }; int opIndex = input.IndexOfAny(operators); if (opIndex == -1) { Console.WriteLine("Invalid format! Use something like '5+3' or '10/2'"); return false; } // Split input into left and right numbers string leftNum = input.Substring(0, opIndex).Trim(); string rightNum = input.Substring(opIndex + 1).Trim(); // Validate and parse numbers if (!double.TryParse(leftNum, out a) || !double.TryParse(rightNum, out b)) { Console.WriteLine("Invalid numbers in your expression!"); return false; } op = input[opIndex]; return true; } // Correct C# entry point static void Main(string[] args) { Calculator cal = new Calculator(); string line; while (true) { Console.WriteLine("\nEnter (Clear, Undo, Exit, Expression):"); line = Console.ReadLine()?.Trim(); if (string.IsNullOrEmpty(line)) { Console.WriteLine("Please enter a valid command or expression."); continue; } // Use switch for cleaner command handling (case-insensitive) switch (line.ToLower()) { case "exit": Console.WriteLine("Exiting calculator..."); return; case "undo": cal.Undo(); break; case "clear": cal.Clear(); break; default: // Parse and execute the user's expression if (cal.TryParseExpression(line, out double a, out double b, out char op)) { switch (op) { case '+': cal.Add(a, b); break; case '-': cal.Subtract(a, b); break; case '*': cal.Multiply(a, b); break; case '/': cal.Divide(a, b); break; default: Console.WriteLine("Unknown operator!"); break; } } break; } } } }
Key improvements explained:
- Stack Initialization: The stack is created in the
Calculatorconstructor, so it's ready to use as soon as you create a calculator instance. - Fixed Undo: Now we only pop the current result, then set
CurrentTotalto the top of the stack (or 0 if empty) instead of deleting two entries. - Expression Parsing: The
TryParseExpressionmethod takes the user's input (like "7*4") and splits it into valid numbers and an operator, so your calculation methods actually get usable values. - Robust Main Method: We read user input, handle empty entries, and use a switch statement for cleaner command handling (and it's case-insensitive!).
- C# Conventions: Renamed methods/fields to follow standard naming rules, making the code easier to read and maintain.
内容的提问来源于stack exchange,提问作者Maya Wazni
相关产品推荐
相关产品推荐

