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);
                }
        }
}