Friday, May 24, 2013

Alternative to JavaScript’s switch statement in C# (According to Dave Ward)

In the post My favorite alternative to JavaScript’s switch statement Dave Ward showed how to refactor the switch statement to improve code extensibility and maintainability with JavaScript.

This is something I like and use a lot. So I adapted his code samples to C#, in case you will be interested in the syntax. And contrary to what Dave mentioned this is not specific to JavaScript, you can do the same thing with C#, though JavaScript's syntax is cleaner for solution #2.

First a code sample using a switch statment.
public static decimal GetItemPricing_V1(Customer customer, Item item) {

    switch(customer.Type) {

        // VIPs are awesome. Give them 50% off.
        case CustomerType.VIP: return item.Price * item.Quantity * 0.50M;
 
        // Preferred customers are no VIPs, but they still get 25% off.
        case CustomerType.Preferred: return item.Price * item.Quantity * 0.75M;
 
        // No discount for other customers.
        case CustomerType.Regular:
        default:  return item.Price * item.Quantity;
    }
}

Solution #1
public static decimal GetItemPricing_V2(Customer customer, Item item) {

    var Pricing = new Dictionary() {

        { CustomerType.VIP,        0.50M },
        { CustomerType.Preferred,  0.75M }, 
        { CustomerType.Regular,    1M    } 
    };

    if(Pricing.ContainsKey(customer.Type)) 
        return item.Price * item.Quantity * Pricing[customer.Type];
    else
         return item.Price * item.Quantity * Pricing[CustomerType.Regular];
}

Solution #2
public static decimal GetItemPricing_V3(Customer customer, Item item) {

    var Pricing = new Dictionary<CustomerType, Func<Item, Decimal>>() {

        { CustomerType.VIP,        delegate(Item item2) { return item.Price * item.Quantity * 0.50M; } },
        { CustomerType.Preferred,  delegate(Item item2) { return item.Price * item.Quantity * 0.75M; } },
        { CustomerType.Regular,    delegate(Item item2) { return item.Price * item.Quantity * 1M;    } },
    };

    if(Pricing.ContainsKey(customer.Type))
        return Pricing[customer.Type](item);
    else
        return Pricing[CustomerType.Regular](item);
}

Full source code

[TestClass]
public class UnitTest1
{
    public enum CustomerType {
        VIP,
        Preferred,
        Regular
    }
    public class Customer {
        public CustomerType Type;
    }
    public class Item {
        public decimal Quantity;
        public decimal Price;
    }
    public static decimal GetItemPricing_V1(Customer customer, Item item) {

        switch(customer.Type) {
            // VIPs are awesome. Give them 50% off.
            case CustomerType.VIP: return item.Price * item.Quantity * 0.50M;
 
            // Preferred customers are no VIPs, but they still get 25% off.
            case CustomerType.Preferred: return item.Price * item.Quantity * 0.75M;
 
            // No discount for other customers.
            case CustomerType.Regular:
            default:  return item.Price * item.Quantity;
        }
    }
    public static decimal GetItemPricing_V2(Customer customer, Item item) {

        var Pricing = new Dictionary<CustomerType, Decimal>() {
            { CustomerType.VIP,        0.50M },
            { CustomerType.Preferred,  0.75M }, 
            { CustomerType.Regular,    1M    } 
        };
        if(Pricing.ContainsKey(customer.Type)) 
            return item.Price * item.Quantity * Pricing[customer.Type];
        else
                return item.Price * item.Quantity * Pricing[CustomerType.Regular];
    }
    public static decimal GetItemPricing_V3(Customer customer, Item item) {

        var Pricing = new Dictionary<CustomerType, Func<Item, Decimal>>() {
            { CustomerType.VIP,        delegate(Item item2) { return item.Price * item.Quantity * 0.50M; } },
            { CustomerType.Preferred,  delegate(Item item2) { return item.Price * item.Quantity * 0.75M; } },
            { CustomerType.Regular,    delegate(Item item2) { return item.Price * item.Quantity * 1M;    } },
        };

        if(Pricing.ContainsKey(customer.Type))
            return Pricing[customer.Type](item);
        else
            return Pricing[CustomerType.Regular](item);
    }

    Customer vipCustomer = new Customer() { Type = CustomerType.VIP };
    Customer preferredCustomer = new Customer() { Type = CustomerType.Preferred };
    Customer regularCustomer = new Customer() { Type = CustomerType.Regular };

    Item item = new Item() { Price = 100M, Quantity = 10M };

    [TestMethod]
    public void GetItemPricing_V1()
    {
        Assert.AreEqual( 500, GetItemPricing_V1(vipCustomer, item) );
        Assert.AreEqual( 750, GetItemPricing_V1(preferredCustomer, item) );
        Assert.AreEqual( 1000, GetItemPricing_V1(regularCustomer, item) );
    }

    [TestMethod]
    public void GetItemPricing_V2()
    {
        Assert.AreEqual( 500, GetItemPricing_V2(vipCustomer, item) );
        Assert.AreEqual( 750, GetItemPricing_V2(preferredCustomer, item) );
        Assert.AreEqual( 1000, GetItemPricing_V2(regularCustomer, item) );
    }

    [TestMethod]
    public void GetItemPricing_V3()
    {
        Assert.AreEqual( 500, GetItemPricing_V3(vipCustomer, item) );
        Assert.AreEqual( 750, GetItemPricing_V3(preferredCustomer, item) );
        Assert.AreEqual( 1000, GetItemPricing_V3(regularCustomer, item) );
    }
}

1 comment: