Mathematical Expression Parser Sample C# Code

Code:

    public class Calc
    {
        private readonly NodeFactory m_NodeFactory;

        public Calc()
        {
            m_NodeFactory = new NodeFactory();
            m_NodeFactory.Register("+", typeof(AdditionNode));
            m_NodeFactory.Register("*", typeof(MultiplicationNode));
        }

        public double Evaluate(string expression, out string output)
        {
            var node = m_NodeFactory.CreateNode(expression);
            output = node.ToString();
            return node.Evaluate();
        }
    }
    
    public class NodeFactory
    {
        private readonly IDictionary<string, Type> m_OperationNodes;

        public NodeFactory()
        {
            m_OperationNodes = new Dictionary<string, Type>();
        }

        public void Register(string operation, Type nodeType)
        {
            m_OperationNodes.Add(operation, nodeType);
        }

        public Node CreateNode(string expression)
        {
            string[] expressionValues = expression.Split(' ');
            Node prevNode = null;

            for (int i = expressionValues.Length-1; i >= 0; i--)
            {
                Type operationType;
                if (!m_OperationNodes.TryGetValue(expressionValues[i], out operationType))
                {
                    ValueNode vNode = new ValueNode(Convert.ToDouble(expressionValues[i]));
                    if (prevNode == null) prevNode = vNode;
                    else ((OperationNode)prevNode).Left = vNode;
                    continue;
                }

                OperationNode oNode = (OperationNode)Activator.CreateInstance(operationType);
                oNode.Right = prevNode;
                prevNode = oNode;
            }

            return prevNode;
        }
    }
    
    public abstract class OperationNode : Node
    {
        public Node Left;
        public Node Right;
    }

    public class AdditionNode : OperationNode
    {
        public override double Evaluate()
        {
            return Left.Evaluate() + Right.Evaluate();
        }

        public override string ToString()
        {
            return Left + " + " + Right;
        }
    }

    public class MultiplicationNode : OperationNode
    {
        public override double Evaluate()
        {
            return Left.Evaluate() * Right.Evaluate();
        }

        public override string ToString()
        {
            return Left + " * " + Right;
        }
    }

    public abstract class Node
    {
        public abstract double Evaluate();
    }

    public class ValueNode : Node
    {
        private readonly double m_Value;

        public ValueNode(double value)
        {
            m_Value = value;
        }

        public override double Evaluate()
        {
            return m_Value;
        }

        public override string ToString()
        {
            return m_Value.ToString();
        }
    }

Test:

    [TestFixture]
    public class CalcTest
    {
        [TestCase("1 + 1", 2)]
        [TestCase("1 + 1 + 2", 4)]
        [TestCase("1 + 2 * 3", 7)]
        [TestCase("1 + 2 * 3 * 4", 25)]
        public void AdditionAndMultiplication(string value, double expected)
        {
            // arrange
            var calc = new Calc();

            // act
            string actualText;
            double actual = calc.Evaluate(value, out actualText);

            // assert
            Assert.AreEqual(expected, actual);
            Assert.AreEqual(value, actualText);
        }
    }