# Tuesday, August 25, 2009
« Topical: The use of the var keyword revi... | Main | Interview Question: Have you ever had an... »

Earlier today, I blogged an interview question about reflection. Earlier this year, as part of the interviewing process I was tasked to write a simple calculator. There would only be 2 integer inputs with a single operation. For example, if the invoked the program, and entered in 1 U 2 (U being the operation for addition), the program would output 3.

The assignment also mentioned they would want the possibility to expand the operations later. Instead of just commenting on it, I decided to implement that into the design.

I won't go into retrieving the data from command prompt, but I will provide the project at the end and you can see how that is accomplished. I made it robust by accounting for spaces, etc. As a programming concept, you should always program defensively and assume the work (and you'll be glad with the results).

First, I created a base class each operand would inherit from, so that each works similarly. The base class OperationBase looks like this:

using System.Diagnostics;

 

namespace CalcLibrary

{

    [OperatorIndex("")]

    public abstract class OperationBase

    {

        private int value1;

        private int value2;

        private string errorInformation = String.Empty;

 

        public int Value1

        {

            get { return value1; }

            set { value1 = value; }

        }

 

        public int Value2

        {

            get { return value2; }

            set { value2 = value; }

        }

 

        public string ErrorInformation

        {

            get { return errorInformation; }

            private set { errorInformation = value; }

        }

 

        //NOTE: We may want to return a string as the division will round every time, but we will keep this as an int

        public abstract int Calculate();

 

        protected void ErrorHandler(Exception ex)

        {

            try

            {

                //While in a production app we would want to hide the internals of an error, in this app we will show them

                this.ErrorInformation = "An unexpected error occurred (" + new StackTrace().GetFrame(2).GetMethod().Name + ")-" + ex.Message;

            }

            catch  {}

        }

 

    }

}

You'll notice this abstract class defines taking two int inputs (Value1 and Value2), handles the errors, and forces every implementation to provide a definition of the "Calculate" method. When inheriting from this class, any operand will be very simple to define -- all it needs to do is determine what to do for a Calculation, as seen by the addition operand implementation.

 

namespace CalcLibrary

{

    [OperatorIndex("U")]

    public class AdditionOperand : OperationBase

    {

        public override int Calculate()

        {

            return this.Value1 + this.Value2;

        }

    }

}

 

The next task was to determine which operand to use given the user's input. We could write an "if" statement or a factory method, but I wanted to make sure if anyone came in to add a new operand, they would not have to change any code -- just add a new class, inherit from OperationBase and implement the Calculate() method. To accomplish this task, I decided to use reflection. By decorating each Operand class with an attribute, I could designate how it reacts to the inputs.

 

First, I needed to define my attribute:

 

using System;

 

namespace CalcLibrary

{

    [System.AttributeUsage(System.AttributeTargets.Class)]

    public class OperatorIndex : System.Attribute

    {

        public string OperatorId = String.Empty;

        public OperatorIndex(string operatorId)

        {

            OperatorId = operatorId;

        }

    }

}

 

Next, I need to decorate my operands with the appropriate attribute. Again, I will use the AdditionOperand, which is indicated by the "U" notation. When I define my class, I decorate it with the attribute letter I want to use to define that function.

 

    [OperatorIndex("U")]

    public class AdditionOperand : OperationBase

 

Now that I have defined my operations, I need to use them. I created a publically exposed static class called CalcEngine which loads all the operations, validates the inputs, and processes the calculations. I created this as a class library so it could be used with a console application (as it is being called from in the supplied example), a web application, etc.

 

In the constructor, I call a method LoadOperators() which uses LINQ to Reflection to quickly retrieve all classes of type OperatorBase and have the OperatorIndex defined. I load the resules into a dictionary object so I can quickly retrieve them for my calculations. Below is how I load the operators using LINQ to Reflection.

 

private static void LoadOperators()

        {

            //Using LINQ to Reflection, load all classes from the assembly that inherit from our base Operator type,

            //and have the attribute set into a dictionary, so we can quickly reference the operator we want

            operations =

                (from a in AppDomain.CurrentDomain.GetAssemblies()

                from t in a.GetTypes()

                where Attribute.IsDefined(t,typeof(OperatorIndex))

                where t.BaseType == typeof(OperationBase)

                let attribute = Attribute.GetCustomAttribute(t,typeof(OperatorIndex)) as OperatorIndex

                where attribute.OperatorId != ""

                select

                    new OperatorDetails

                    {

                        AssemName = a.GetName().Name,

                        ClassName = t.FullName,

                        OperatorId = attribute.OperatorId

                    }).ToDictionary(p => p.OperatorId,p => p);

 

        }

The main Calculate method validates the input, retrieves the right operand key from the dictionary, late binds to the proper OperatorBase class and invokes the Calculate() method, as seen below.

 

                //locate the correct operator from our dictionary

                OperatorDetails operatorInfo = operations[mathOperator];

 

                //dynamically load the operator class. I chose to do it using reflection so that we wouldn't need a

                //factory, which would need to be changed every time a new operator was added.

                //ENHANCEMENT: you could actually detect other assemblies and load them as well

                Type calcClass = Type.GetType(operatorInfo.ClassName);

                OperationBase calculator = (OperationBase) Activator.CreateInstance(calcClass);

                calculator.Value1 = value1;

                calculator.Value2 = value2;

                int calculatedResult = calculator.Calculate();

 
Using a console application, it looks like this:
 

Here's the sample code to look at and play with.. Enjoy!

 

SampleProj.zip (89.4 KB)