Wednesday, October 23, 2013

Stack Implementation using Managed Extensibility Framework

Hi Guys,

This time I made a small application to simulate a basic stack data structure. But to make things interesting I used Managed Extensibility Framework.

Before you Start,

1) Visual Studio with .NET Framework 4 or higher (Any Version)

Step One : The Solution

Create a console application project and a class library as shown in the image. Refer both the projects with System.ComponentModel.Composition. And add a reference to Console Application from the class library.

















Step Two : The Code

Paste the following code in the Program.cs file of MEFClient Project. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace MEFClient
{
    //Stack Implementation 
    [Export(typeof(IStack))]
    class MySimpleStack : IStack
    {
        [ImportMany]
        IEnumerable<Lazy<IOperation, IOperationData>> operations;
        int[] arr = { -1, -1, -1, -1, -1 };

        public String Process(String input)
        {
            string command;
            int val;


            int fn = FindSeperator(input); //finds the operator
            if (fn < 0) return "Could not parse command.";

            try
            {
                //separate out the operands
                command = input.Substring(0, fn);
                val = int.Parse(input.Substring(fn + 1));
            }
            catch
            {
                return "Could not parse command.";
            }



            foreach (Lazy<IOperation, IOperationData> i in operations)
            {
                if (i.Metadata.Command.Equals(command)) return i.Value.Manipulate(arr, val).ToString();
            }
            return "Operation Not Found!";
        }

        private int FindSeperator(String s)
        {

            for (int i = 0; i < s.Length; i++)
            {
                if (s[i] == ':') return i;
            }
            return -1;
        }


    }


    class Program
    {

        private CompositionContainer _container;

        [Import(typeof(IStack))]
        public IStack stack;


        private Program()
        {
            //An aggregate catalog that combines multiple catalogs
            var catalog = new AggregateCatalog();
            //Adds all the parts found in the same assembly as the Program class
            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
            //Location of the directory of extensions
            catalog.Catalogs.Add(new DirectoryCatalog(@"C:\Users\Shahim\Documents\visual studio 2012\Projects\TestApplication\Extensions\bin\Debug"));


            //Create the CompositionContainer with the parts in the catalog
            _container = new CompositionContainer(catalog);

            //Fill the imports of this object
            try
            {
                this._container.ComposeParts(this);
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }
        }

        static void Main(string[] args)
        {
            Program p = new Program(); //Composition is performed in the constructor
            String s;
            Console.WriteLine("Enter Command:");
            while (true)
            {
                s = Console.ReadLine();
                Console.WriteLine(p.stack.Process(s));
            }

        }
    }

    //Interface for the stack
    public interface IStack
    {
        String Process(String input);
    }

    //Interface for the operation 
    public interface IOperation
    {
        String Manipulate(int[] arr, int val);
    }

    // //Interface for the operation data 
    public interface IOperationData
    {
        String Command { get; }
    }

    //Push Implemenation
    [Export(typeof(IOperation))]
    [ExportMetadata("Command", "PUSH")]
    class Push : IOperation
    {
        public String Manipulate(int[] arr, int val)
        {
            bool pushed = false;

            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] == -1)
                {
                    arr[i] = val;
                    pushed = true;
                    break;
                }
            }

            return pushed ? "Value Pushed!" : "Value Was Not Pushed!";
        }
    }

}

Paste the following code in the ExtensionClass.cs file of Extensions Project. 

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Extensions
{
    //Pop Implementation
    [Export(typeof(MEFClient.IOperation))]
    [ExportMetadata("Command", "POP")]
    class Pop : MEFClient.IOperation
    {
        public String Manipulate(int[] arr, int val)
        {
            bool poped = false;
            int valuePoped = -1;

            for (int i = arr.Length - 1; i >= 0; i--)
            {
                if (arr[i] != -1)
                {
                    valuePoped = arr[i];
                    arr[i] = -1;
                    poped = true;

                    break;
                }
            }

            return valuePoped.ToString() + (poped ? " Value Poped!" : " Value Was Not Poped!");
        }
    }

    //Show Implementation
    [Export(typeof(MEFClient.IOperation))]
    [ExportMetadata("Command", "SHOW")]
    class Show : MEFClient.IOperation
    {
        public String Manipulate(int[] arr, int val)
        {
            string arrStr = string.Empty;

            for (int i = arr.Length - 1; i >= 0; i--)
            {
                arrStr += arr[i].ToString() + ",";
            }

            return arrStr.Substring(0, arrStr.Length - 1);
        }
    }

}

Step Three : Running the Program