Download the .cs file here
#define CSHARP7

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace Benchmarking
{
    public class CastTesting
    {
        class Result
        {
            public long Time { get; set; }
            public string Label { get; set; }
        }

        public static Type A()
        {
            return typeof(A);
        }

        public static void Main()
        {
            Console.WriteLine("Starting benchmark...");

            SortedDictionary<long, string> results = new SortedDictionary<long, string>();
            Console.WriteLine("Starting baseline...");
            long baseline = BenchmarkType(new Baseline());
            Console.WriteLine("Finished baseline. Baseline = {0}ms.", baseline);
            var casters = (from t in typeof(CastTesting).Assembly.GetTypes()
                         where t.GetInterface("ICaster") != null && t.Name != "Baseline" && t.GetConstructor(Type.EmptyTypes) != null
                         select (ICaster)Activator.CreateInstance(t)).ToArray();
            for (int i = 0; i < casters.Length; ++i)
            {
                var caster = casters[i];
                string name = caster.GetType().Name;
                Console.WriteLine("Beginning {0}", name);
                long result = BenchmarkType(caster);
                results[result] = name;
                Console.WriteLine("Done with {0} in {3}: {1}/{2}", name, i, casters.Length, result);
            }

            long fastestTime = results.First().Key - baseline;
            foreach (var kvp in results)
            {
                long thisTime = kvp.Key - baseline;
                double slowDown = (1 - 1.0 * fastestTime / thisTime) * 100;
                Console.WriteLine("{0,-40}: {1,-8}  {2:0.##}% slower than fastest.", kvp.Value, thisTime, slowDown);
            }

            Console.WriteLine();
            Console.WriteLine("Adjusted for a baseline of {0} milliseconds.", baseline);
            Console.WriteLine("Processing done! Press any key to quit.");
            Console.ReadKey();
        }

        const long Iterations = 9000000000;

        static long BenchmarkType(ICaster caster)
        {
            var doer = new Doer();
            GC.Collect();
            var watch = Stopwatch.StartNew();
            for (long i = 0; i < Iterations; ++i)
            {
                caster.Do(new A(), doer);
                caster.Do(new B(), doer);
                caster.Do(new C(), doer);
                caster.Do(new D(), doer);
                caster.Do(new E(), doer);
                caster.Do(new F(), doer);
            }
            return watch.ElapsedMilliseconds;
        }
    }

    public interface ICaster
    {
        void Do(IDo o, Doer doer);
    }

    public class Baseline : ICaster
    {
        public void Do(IDo o, Doer doer) { }
    }

    public class TypeDictionary : ICaster
    {
        static Dictionary<Type, Action<Doer, object>> s_dict = new Dictionary<Type, Action<Doer, object>>()
        {
            { typeof(A), (d, o) => d.Do((A)o) },
            { typeof(B), (d, o) => d.Do((B)o) },
            { typeof(C), (d, o) => d.Do((C)o) },
            { typeof(D), (d, o) => d.Do((D)o) },
            { typeof(E), (d, o) => d.Do((E)o) },
            { typeof(F), (d, o) => d.Do((F)o) },
        };

        public void Do(IDo o, Doer doer)
        {
            Action<Doer, object> actor;
            s_dict.TryGetValue(o.GetType(), out actor);
            actor(doer, o);
        }
    }

    public class HandleDict : ICaster
    {
        static Dictionary<RuntimeTypeHandle, Action<Doer, object>> s_dict = new Dictionary<RuntimeTypeHandle, Action<Doer, object>>()
        {
            { typeof(A).TypeHandle, (d, o) => d.Do((A)o) },
            { typeof(B).TypeHandle, (d, o) => d.Do((B)o) },
            { typeof(C).TypeHandle, (d, o) => d.Do((C)o) },
            { typeof(D).TypeHandle, (d, o) => d.Do((D)o) },
            { typeof(E).TypeHandle, (d, o) => d.Do((E)o) },
            { typeof(F).TypeHandle, (d, o) => d.Do((F)o) }
        };

        public void Do(IDo o, Doer doer)
        {
            s_dict[Type.GetTypeHandle(o)](doer, o);
        }
    }

    public class HandleElse : ICaster
    {
        static RuntimeTypeHandle s_a = typeof(A).TypeHandle;
        static RuntimeTypeHandle s_b = typeof(B).TypeHandle;
        static RuntimeTypeHandle s_c = typeof(C).TypeHandle;
        static RuntimeTypeHandle s_d = typeof(D).TypeHandle;
        static RuntimeTypeHandle s_e = typeof(E).TypeHandle;
        static RuntimeTypeHandle s_f = typeof(F).TypeHandle;

        public void Do(IDo o, Doer doer)
        {
            var handle = Type.GetTypeHandle(o);
            if (handle.Equals(s_a)) doer.Do((A)o);
            else if (handle.Equals(s_b)) doer.Do((B)o);
            else if (handle.Equals(s_c)) doer.Do((C)o);
            else if (handle.Equals(s_d)) doer.Do((D)o);
            else if (handle.Equals(s_e)) doer.Do((E)o);
            else if (handle.Equals(s_f)) doer.Do((F)o);
        }
    }

    public class IfIsCStyle : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            if (o is A)
                ((A)o).Do(doer);
            else if (o is B)
                ((B)o).Do(doer);
            else if (o is C)
                ((C)o).Do(doer);
            else if (o is D)
                ((D)o).Do(doer);
            else if (o is E)
                ((E)o).Do(doer);
            else if (o is F)
                ((F)o).Do(doer);
        }
    }

    public class TypeElse : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            var type = o.GetType();
            if (type == typeof(A)) doer.Do((A)o);
            else if (type == typeof(B)) doer.Do((B)o);
            else if (type == typeof(C)) doer.Do((C)o);
            else if (type == typeof(D)) doer.Do((D)o);
            else if (type == typeof(E)) doer.Do((E)o);
            else if (type == typeof(F)) doer.Do((F)o);
        }
    }

    public class CastAsEachTime : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            var a = o as A;
            var b = o as B;
            var c = o as C;
            var d = o as D;
            var e = o as E;
            var f = o as F;

            if (a != null)
                doer.Do(a);
            else if (b != null)
                doer.Do(b);
            else if (c != null)
                doer.Do(c);
            else if (d != null)
                doer.Do(d);
            else if (e != null)
                doer.Do(e);
            else if (f != null)
                doer.Do(f);
        }
    }

    public class Polymorphic : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            o.Do(doer);
        }
    }

    public class CastWithElse : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            var a = o as A;
            if (a != null)
                doer.Do(a);
            else
            {
                var b = o as B;
                if (b != null)
                    doer.Do(b);
                else
                {
                    var c = o as C;
                    if (c != null)
                        doer.Do(c);
                    else
                    {
                        var d = o as D;
                        if (d != null)
                            doer.Do(d);
                        else
                        {
                            var e = o as E;
                            if (e != null)
                                doer.Do(e);
                            else
                            {
                                var f = o as F;
                                if (f != null)
                                    doer.Do(f);
                            }
                        }
                    }
                }
            }
        }
    }

#if CSHARP7
    public class PatternMatchIfElse : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            if (o is A a)
                doer.Do(a);
            else if (o is B b)
                doer.Do(b);
            else if (o is C c)
                doer.Do(c);
            else if (o is D d)
                doer.Do(d);
            else if (o is E e)
                doer.Do(e);
            else if (o is F f)
                doer.Do(f);
        }
    }

    public class PatternMatchSwitch : ICaster
    {
        public void Do(IDo o, Doer doer)
        {
            switch (o)
            {
                case A a: doer.Do(a); break;
                case B b: doer.Do(b); break;
                case C c: doer.Do(c); break;
                case D d: doer.Do(d); break;
                case E e: doer.Do(e); break;
                case F f: doer.Do(f); break;
            }
        }
    }
#endif

    public interface IDo { void Do(Doer doer); }

    public class A : IDo { public void Do(Doer doer) { ++doer.Count; } }
    public class B : IDo { public void Do(Doer doer) { ++doer.Count; } }
    public class C : IDo { public void Do(Doer doer) { ++doer.Count; } }
    public class D : IDo { public void Do(Doer doer) { ++doer.Count; } }
    public class E : IDo { public void Do(Doer doer) { ++doer.Count; } }
    public class F : IDo { public void Do(Doer doer) { ++doer.Count; } }

    public class Doer
    {
        // Storing the number of iterations
        // just so the compiler can't optimize
        // away all the hard work we're benchmarking.
        public long Count;

        public void Do(A a) { a.Do(this); }
        public void Do(B b) { b.Do(this); }
        public void Do(C c) { c.Do(this); }
        public void Do(D d) { d.Do(this); }
        public void Do(E e) { e.Do(this); }
        public void Do(F f) { f.Do(this); }
    }

    //public class TryCatchC : ICaster
    //{
    //    public void Do(IDo o, Doer doer)
    //    {
    //        try
    //        {
    //            ((A)o).Do(doer);
    //        }
    //        catch (InvalidCastException)
    //        {
    //            try
    //            {
    //                ((B)o).Do(doer);
    //            }
    //            catch (InvalidCastException)
    //            {
    //                try
    //                {
    //                    ((C)o).Do(doer);
    //                }
    //                catch (InvalidCastException)
    //                {
    //                    try
    //                    {
    //                        ((D)o).Do(doer);
    //                    }
    //                    catch (InvalidCastException)
    //                    {
    //                        try
    //                        {
    //                            ((E)o).Do(doer);
    //                        }
    //                        catch (InvalidCastException)
    //                        {
    //                            ((F)o).Do(doer);
    //                        }
    //                    }
    //                }
    //            }
    //        }
    //    }
    //}
}