Click here to Skip to main content
15,886,806 members
Articles / Programming Languages / C#
Tip/Trick

How to perform arithmetic operations between any objects by inheriting a common arithmetic parent class in .NET 4.

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
8 Apr 2011CPOL1 min read 20.1K   3   2
Performing arithmetic operations between objects need to define overloaded operators and restricted to defined types in those method. This code provides an alternate flexible way.
Note: This only works in .NET 4 Framework. Other users, excuse me.
For doing simple arithmatic operations between two objects, we need to overload the operator (+,-,* etc). Also, we need to specify a particular type as the argument in the operator methods. Even a generic operator method is not possible or a very tough task.

So how can we have a parent class which has all the necessary things for doing arithmetic operations and just by inheriting it, any type of child can be subject to arithmetic operations. The flexibility comes from the Microsoft DLR class DynamicObject.

This demo includes a class inherited from DynamicObject which has the arithmetic operations defined. Which in turn inherited by child classes and these child classes can perform arithmetic operations among themselves without any operator overloading methods.
The demo uses two specific namespaces System.Dynamic and System.Linq.Expressions. However all the expressions from the linq.Expressions may not be available with the Dynamic object, but most of the common binary operations available in C# are possible.

The parent class code is as follows:

C#
//Inherits from the Dynamic Object, which enable dynamic language in this object
public class CommonArithmaticObject:DynamicObject
{
    protected Dictionary<string,> dictionary = new Dictionary<string,>();

    public string ErrorMessage { get; set; }

    //Default properties
    public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        return dictionary.TryGetValue(binder.Name, out result);
    }
    public override bool TrySetMember(
        SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }

    //overrided Binary operations method.
    public override bool TryBinaryOperation( BinaryOperationBinder binder, object arg, out object result)
    {
        CommonArithmaticObject obj;
        double resultValue;

        // converting the argument to the CommonArtimaticObject
        //If it is not return false.
        if(arg is CommonArithmaticObject)
        {
            obj=(CommonArithmaticObject)arg;
        }else
        {
            result = null;
            return false;
        }

        //validity checks and if validation fails the objects numeric value will be zero
        double dummy;
        if (obj.dictionary.ContainsKey("Numeric")==false || obj.dictionary["Numeric"] == null)
        {
            obj.dictionary["Numeric"] = 0;
        }
        else if (double.TryParse(obj.dictionary["Numeric"].ToString(),out dummy)==false)
        {
            obj.dictionary["Numeric"] = 0;
        }

        if (dictionary.ContainsKey("Numeric") == false || dictionary["Numeric"] == null)
        {
            dictionary["Numeric"] = 0;
        }
        else if (double.TryParse(dictionary["Numeric"].ToString(), out dummy) == false)
        {
            dictionary["Numeric"] = 0;
        }

        // Dynamic objects binary operations using a switch case block
        try
        {
            switch (binder.Operation)
            {

                case ExpressionType.Add:

                    resultValue =
                        Convert.ToDouble(dictionary["Numeric"]) +
                        Convert.ToDouble(obj.dictionary["Numeric"]);
                    break;

                case ExpressionType.Subtract:
                    resultValue =
                         Convert.ToDouble(dictionary["Numeric"]) -
                         Convert.ToDouble(obj.dictionary["Numeric"]);
                    break;
                case ExpressionType.Multiply:
                    resultValue =
                        Convert.ToDouble(dictionary["Numeric"]) *
                        Convert.ToDouble(obj.dictionary["Numeric"]);
                    break;
                case ExpressionType.Divide:
                    resultValue =
                        Convert.ToDouble(dictionary["Numeric"]) /
                        Convert.ToDouble(obj.dictionary["Numeric"]);
                    break;

                default:
                    result = null;
                    return false;
            }
        }
        catch(Exception e)
        {
            ErrorMessage = e.Message+" "+ e.InnerException !=null ? e.InnerException.Message:"";
            result = null;
            return false;
        }
        // returns a dynamic object of this type.
        dynamic finalResult = new CommonArithmaticObject();
        finalResult.Numeric = resultValue;
        result = finalResult;
        return true;
    }
}

The following classes inherit the above Arithmetic dynamic class.
C#
//These objects may have different members and its numerical representation could be a complex calculation
//For example marks can be a sum of written, practical with criterias like best two etc.,
//So the final numerical representation will be stored in the parent's dictionary with a specific key.
public class Maths : CommonArithmaticObject
{
    private double _marksScored = 0;
    public double MarksScored
    {
        get { return this._marksScored; }

        //setting the numerical representation of the object to the parents dictionary
        set { this._marksScored = value; dictionary.Add("Numeric", MarksScored); }
    }
}

public class Science : CommonArithmaticObject
{
    private double _marksScored = 0;
    public double MarksScored
    {
        get { return this._marksScored; }

        //setting the numerical representation of the object to the parents dictionary
        set { this._marksScored = value; dictionary.Add("Numeric", MarksScored); }
    }
}
public class Language : CommonArithmaticObject
{
    private double _marksScored = 0;
    public double MarksScored
    {
        get { return this._marksScored; }

        //setting the numerical representation of the object to the parents dictionary
        set { this._marksScored = value; dictionary.Add("Numeric", MarksScored); }
    }
}

Now these child classes can perform the defined arithmetic operations among themselves. For example...
C#
//object initialization
dynamic maths = new Maths();
maths.MarksScored = 95;

dynamic science = new Science();
science.MarksScored = 87.65;

dynamic language = new Language();
language.MarksScored = 90;

//Arithmatics.
dynamic totalMarks = maths + science + language;
MessageBox.Show(totalMarks.Numeric.ToString());

dynamic totalExceptLanguage = totalMarks - language;
MessageBox.Show(totalExceptLanguage.Numeric.ToString());


That is it, we are dynamic now. Cheers.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
I am developer in .Net and GIS. albin_gis@yahoo.com

Comments and Discussions

 
Answer- in case ExpressionType.Multiply Pin
Riz Thon4-Apr-11 18:23
Riz Thon4-Apr-11 18:23 
GeneralRe: - in case ExpressionType.Multiply Pin
Albin Abel4-Apr-11 18:35
Albin Abel4-Apr-11 18:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.