Pages

Search

Friday, February 1, 2013

IQueryable and IEnumerable



There is already a post regarding the differences of “IQueryable” and “IEnumerable” published.
Please consider below sample code to understand the difference and usuage of IQueryable and IEnumerable.
//finding the user based on user id (1), using iqueryable.
                user=db.Users.AsQueryable().Where(u => u.UserID == 1).SingleOrDefault();

//finding the user based on user id (1), using ienumerable.
                user = db.Users.AsEnumerable().SingleOrDefault(u =>
                    {
                       return u.UserID == 1;
                    });
Using “IQueryable “, it is the role of the dataprovider (sql or oracle or any db source) to apply the filters or ordering data etc…
“IQueryable” inturn implements “IEnumerable”, to iterate or fetch the data after running the iqueryable expression and store in local memory.
So “IEnumerable” is not playing a role of applying the filters, but helps to read the data executing the query expression. Unless, enumerator of “IQueryable” is invoked the expression will not be executed.
In case of “IEnumerable” with out “IQueryable”, any filters which are applied like (where, count etc…) or any other predicates of linq are applied in the local memory.

Observe below intellitrace screen shots to understand better.

IQueryable – debug intellitrace
(sql Where clause is applied while executing the sql query (sql query build from linq expression using sql provider).




IEnumerable – debug intellitrace
Normal sql with out where clause, but the filtering is applied in memory after fetching the records.

Wednesday, January 30, 2013

Finite State Machine – Beverage Vending Machine


 Finite state machine is a mathematical computation model.

Considering a machine which has finite number of possible states, and there will be only one state in which the machine is said to be in.
Ex:- Vending machine could be in sleep mode or requesting coins from user etc…
The machine may change its state, which could depend upon the triggers.
Ex:- User inserting coins into the machine, might change the machine state from sleep to accepting the coins.
Each state would have next possible states which are associated.

State Machine Diagram :

Below is the sample code, which works using state machine algorithm.

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

namespace StateMachine_BeverageVendingMachine
{
    class Program
    {
        static void Main(string[] args)
        {
            //creating vending machine instance and setting default product cost
            BeverageVendingMachine machine = new BeverageVendingMachine() { Cost = 10 };

            while (true)
            {
                try
                {
                    Console.WriteLine("Current State : " + machine.ToString());

                    //if machine state is sleep, then asking user to enter coins
                    if (machine.CurrentState == MachineState.Sleep)
                    {
                        Console.WriteLine("Please enter coins for amount : " + (machine.Cost - machine.Amount));
                        Int32 coin = GetValidOption((i) =>i>0 && i <= (machine.Cost - machine.Amount), "Please enter coins for amount : " + (machine.Cost - machine.Amount));
                        machine.AddCoins(coin);
                    }

                    //if machine state is coins status, then asking for the remaining amount or either giving a cancel option
                    if (machine.CurrentState == MachineState.Coin_Status)
                    {
                        Console.WriteLine("Please enter coins for amount : " + (machine.Cost - machine.Amount) + " or hit -1 to cancel");
                        Int32 coin = GetValidOption((i) => i > 0 && i <= (machine.Cost - machine.Amount) || i == -1, "Please enter coins for amount : " + (machine.Cost - machine.Amount) + " or hit -1 to cancel");
                        if (coin == -1)
                            machine.Cancel();
                        else
                            machine.AddCoins(coin);
                    }

                    //if machine state is active, then asking user to select beverage option
                    if (machine.CurrentState == MachineState.Active)
                    {
                        Console.WriteLine("Please select menu \n 1. coffee\n 2. Tea");
                        Int32 coin = GetValidOption((i) => i == 1 || i == 2, "Please select menu \n 1. coffee\n 2. Tea");
                        if (coin == 1)
                            machine.Product = "Coffee";
                        if (coin == 2)
                            machine.Product = "Tea";

                        //supplyin the selected product
                        machine.Supply();
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine("Error : " + exp.Message);
                }
            }
        }


        public static Int32 GetValidOption(Func<int, bool> validate, string msg)
        {
            while (true)
            {
                Int32 option = 0;
                if (int.TryParse(Console.ReadLine(), out option))
                {
                    if (validate(option))
                        return option;
                    else
                        Console.WriteLine(msg);
                }
                else
                    Console.WriteLine("Please enter valid number");
            }
        }
    }

    public class BeverageVendingMachine
    {
        Dictionary<StateTransition, MachineState> machineTransitions = null;

        public MachineState CurrentState { get; set; }

        public int Amount { get; set; }

        public int Cost { get; set; }

        public string Product { get; set; }

        public BeverageVendingMachine()
        {
            //adding each possible statetransition for a given state to dictionary.
            machineTransitions = new Dictionary<StateTransition, MachineState>()
            {
                { new StateTransition(MachineState.Sleep,MachineCommand.Sleep2CoinCheck), MachineState.Coin_Check},
                { new StateTransition(MachineState.Coin_Status,MachineCommand.CoinStatus2Cancel), MachineState.Cancel},
                { new StateTransition(MachineState.Coin_Check,MachineCommand.CoinCheck2CointStatus), MachineState.Coin_Status},
                { new StateTransition(MachineState.Coin_Status,MachineCommand.CoinStatus2Active), MachineState.Active},
                { new StateTransition(MachineState.Active,MachineCommand.Active2Supply), MachineState.Supply},
                { new StateTransition(MachineState.Supply,MachineCommand.Supply2Sleep), MachineState.Sleep},
                { new StateTransition(MachineState.Cancel,MachineCommand.Cancel2Sleep), MachineState.Sleep}
            };
            this.CurrentState = MachineState.Sleep;
        }

        //when user inserts coins
        public void AddCoins(Int32 coin)
        {

            //In sleep state the amount is 0, hence changing the state to coin check state
            if (Amount == 0)
                GetNextState(MachineCommand.Sleep2CoinCheck);

            //adding the total amount inserted so far
            Amount += coin;

            //if amount collected is same as cost
            if (Amount == Cost)
            {
                //changing the coin check to coin status and then coin status to active
                if (CurrentState == MachineState.Coin_Check)
                    GetNextState(MachineCommand.CoinCheck2CointStatus);
                GetNextState(MachineCommand.CoinStatus2Active);
            }
            else
                //changing coin check to coin status, when user enters coins, but the amount is less than the actual cost
                if (CurrentState == MachineState.Coin_Check)
                    GetNextState(MachineCommand.CoinCheck2CointStatus);
        }

        //If user selects cancel operation, after entering few coins
        public void Cancel()
        {
            //changing the state to cancel and sleep
            GetNextState(MachineCommand.CoinStatus2Cancel);
            GetNextState(MachineCommand.Cancel2Sleep);

            //handovering the amout collected before cancel
            if (Amount > 0)
                Console.WriteLine("Please collect your amount : {0}", Amount);
            Amount = 0;
        }

        //after user selects product from menu
        public void Supply()
        {
            //supplying the product
            GetNextState(MachineCommand.Active2Supply);
            Console.WriteLine("Supplying {0} ...", Product);

            //going to sleep mode
            GetNextState(MachineCommand.Supply2Sleep);
            Console.WriteLine("Thanks for choosing this vending machine");
            Amount = 0;
        }

        //setting the next state based on current state and command issued
        public void GetNextState(MachineCommandcommand)
        {
            StateTransition trans = new StateTransition(CurrentState, command);
            MachineState nextState;
            if (machineTransitions.TryGetValue(trans, out nextState))
            {
                CurrentState = nextState;
            }
            else
                throw new Exception(string.Format("No valid state transition for state : {0}, command : {1}", CurrentState, command));
        }

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


    //each state transition object is the reference of StateTransition class

    public class StateTransition
    {
        readonly MachineState CurrentState;
        readonly MachineCommandCommand;
        public StateTransition(MachineState state, MachineCommand command)
        {
            this.CurrentState = state;
            this.Command = command;
        }
        public override bool Equals(object obj1)
        {
            StateTransition obj = obj1 as StateTransition;
            return (obj.Command == this.Command && obj.CurrentState == this.CurrentState);
        }
        public override int GetHashCode()
        {
            return (10 * CurrentState.GetHashCode()) + (10 * Command.GetHashCode());
        }
    }

    //Vending machine, finite possible states
    public enum MachineState
    {
        Sleep = 1,
        Coin_Check = 2,
        Cancel = 3,
        Coin_Status = 4,
        Active = 5,
        Supply = 6
    }

    //Vending machine, possible state transitions
    public enum MachineCommand
    {
        Sleep2CoinCheck = 1,
        CoinStatus2Cancel = 2,
        Cancel2Sleep = 3,
        CoinCheck2CointStatus = 4,
        CoinStatus2Active = 5,
        Active2Supply = 6,
        Supply2Sleep = 7
    }
}

Output :