You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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 result stack 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), not int main().
    • You never instantiated your Calculator class or read user input into line.
    • The expression parsing section doesn't actually split the user's input into numbers and an operator, so variables a, b, and c are unassigned.
  • Flawed Clear Method: Again, result.DefaultIfEmpty() is used incorrectly here, and looping to pop each element is unnecessary (Stack has a built-in Clear() 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:

  1. Stack Initialization: The stack is created in the Calculator constructor, so it's ready to use as soon as you create a calculator instance.
  2. Fixed Undo: Now we only pop the current result, then set CurrentTotal to the top of the stack (or 0 if empty) instead of deleting two entries.
  3. Expression Parsing: The TryParseExpression method 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.
  4. Robust Main Method: We read user input, handle empty entries, and use a switch statement for cleaner command handling (and it's case-insensitive!).
  5. C# Conventions: Renamed methods/fields to follow standard naming rules, making the code easier to read and maintain.

内容的提问来源于stack exchange,提问作者Maya Wazni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:23:49