File: Program.cs - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

���using System;

namespace GenericMethodBinder
{
    static class ExtensionMethods
    {
        public static void StringMethod(this string text)
        {
            Console.Write("This the specific extension method for the type string with the text ");
            Console.WriteLine(text);
        }

        public static void GenericMethod<T>(this T value)
        {
            Console.Write("This is the generic Extension Method for the type ");
            Console.Write(typeof(T).ToString());
            Console.Write(" called with the value ");
            Console.WriteLine(value.ToString());
        }
    }

    static class MethodBuilder<T>
    {
        static string text;

        static MethodBuilder()
        {
            text = "This is the generic Method for the type " + typeof(T).Name + " called with the value ";
        }

        public static void Method(T value)
        {
            Console.Write(text);
            Console.WriteLine(value.ToString());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("We are going to play with three method types:");
            Console.WriteLine(" - Method from a generic type, using the type parameter");
            Console.WriteLine(" - Generic extension method");
            Console.WriteLine(" - Specific extension method (which is the same as a regular method)");
            Console.WriteLine("Direct usage of the methods with the string type, just to show you what happens...");
            MethodBuilder<string>.Method("toto");
            "toto".GenericMethod();
            "toto".StringMethod();
            Console.WriteLine();

            Console.WriteLine("Binding the various methods using MethodManager...");
            MethodManager.Bind<int>(MethodBuilder<int>.Method);
            MethodManager.Bind<float>(MethodBuilder<float>.Method);
            MethodManager.Bind<string>(ExtensionMethods.StringMethod);
            MethodManager.Bind<short>(ExtensionMethods.GenericMethod);
            MethodManager.Bind<double>(ExtensionMethods.GenericMethod);
            Console.WriteLine();

            Console.WriteLine("Using the methods with MethodCaller...");
            new MethodCaller<int>(42).CallMethod();
            new MethodCaller<float>(0.5f).CallMethod();
            new MethodCaller<string>("bla bla bla").CallMethod();
            new MethodCaller<short>(33).CallMethod();
            new MethodCaller<double>(666).CallMethod();
            Console.WriteLine();

            Console.WriteLine("And finally, we try to use the MethodManager asking for an uninitialized method...");
            try
            {
                new MethodCaller<char>('@').CallMethod();
                Console.WriteLine("And the call is successful.");
            }
            catch (NullReferenceException e)
            {
                Console.WriteLine("And the call is unsuccessful.");
                Console.WriteLine(e.Message);
            }
            Console.WriteLine();

            Console.WriteLine("We could check the bindings before trying to use them, like this: ");
            TestBinding<int>();
            TestBinding<string>();
            TestBinding<float>();
            TestBinding<decimal>();
            TestBinding<double>();
            TestBinding<char>();
            TestBinding<byte>();
            TestBinding<short>();
            Console.WriteLine();

            Console.WriteLine("That's it.");
        }

        static void TestBinding<T>()
        {
            Console.WriteLine("The method for type " + typeof(T).Name + " is " + (MethodManager.IsBound<T>() ? string.Empty : "not ") + "bound.");
        }
    }

    delegate void MethodDelegate<T>(T value);

    static class MethodManager
    {
        static class MethodHolder<T>
        {
            public static MethodDelegate<T> Method;
        }

        public static void Bind<T>(MethodDelegate<T> method)
        {
            MethodHolder<T>.Method = method;
        }

        public static void CallMethod<T>(T value)
        {
            MethodHolder<T>.Method(value);
        }

        public static bool IsBound<T>()
        {
            return MethodHolder<T>.Method != null;
        }
    }

    public class MethodCaller<T>
    {
        T value;

        public MethodCaller(T value)
        {
            this.value = value;
        }

        public void CallMethod()
        {
            MethodManager.CallMethod(value);
        }
    }
}