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)