Friday, May 06, 2016

C# Switch on Type

I want to write readable code like below to handle different sub types. Let’s say if I want to take a shower for my pets. Depending on the pet type, I will like to handle it differently. As you can tell, if statements can do the work but it will be very messy. I would like to use switch statement. However, C# compiler doesn’t want to get into this business. That’s alright. I will like to do it myself. Here is a clean solution. The ultmiate code is very easy to read. No if statements. Zero. None. Nil. There are 3 simple steps.

myPet.Switch()
     .Case<Dog>(x => HandleDog(x))
     .Case<Cat>(x => HandleCat(x))
     .Case<Parrot>(x => HandleParrot(x))
     .Default<Pet>(x => HandleDefault(x));

Step 1: Create a Switch class.

public class Switch
{
    public Switch(object o)
    {
        Target = o;
    }

    public object Target { get; set; }
}

 

Step 2: Create extension methods to support fluent API, supporting, predict, fall through, and default.

public static class SwitchExtensions
{
    public static Switch Case<T>(this Switch switcher, 
        Action<T> action) where T : class
    {
        return Case(switcher, o => true, action, false);
    }

    public static Switch Case<T>(this Switch switcher, 
        Action<T> action, 
        bool fallThrough) where T : class
    {
        return Case(switcher, o => true, action, fallThrough);
    }

    public static Switch Case<T>(this Switch switcher, 
        Func<T, bool> predicate, 
        Action<T> action) where T : class
    {
        return Case(switcher, predicate, action, false);
    }

    public static Switch Case<T>(this Switch s, 
        Func<T, bool> predicate, 
        Action<T> action, 
        bool fallThrough) where T : class
    {
        if (s == null)
        {
            return null;
        }

        var t = s.Target as T;
        if (t == null)
        {
            return s;
        }

        if (!predicate(t))
        {
            return s;
        }

        action(t);
        return fallThrough ? s : null;
    }

    public static void Default<T>(this Switch switcher, 
        Action<T> action) where T : class
    {
        if (switcher == null)
        {
            return;
        }

        var t = switcher.Target as T;
        if (t == null)
        {
            return;
        }

        action(t);
    }
}
Step 3: Finally, add an extension method for System.Object so that any object can call Switch() method.
public static class ObjectSwitchExtensions
{
    public static Switch Switch(this object Object)
    {
        return new Switch(Object);
    }
}

Thumbs Up to GitHub Copilot and JetBrains Resharper

Having used AI tool GitHub Copilot since 08/16/2023, I’ve realized that learning GitHub Copilot is like learning a new framework or library ...