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