web analytics

Understanding Extension Methods in C#

Options

codeling 1599 - 6654
@2016-02-05 08:21:23

One of the numerous exciting new features since C# 3.0 is extension methods: static methods that you can invoke using the instance method syntax.

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C#, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

To declare an extension method, you specify the keyword this as the first parameter of the method, for example:

// Program.cs
public static class StringExtension
{
   public static int ToInt32Ext(this string s)
   {
      return Int32.Parse(s);
   }
   public static int ToInt32Static(string s)
   {
      return Int32.Parse(s);
   }
}
class Program
{
   static void Main(string[] args)
   {
      string s = "9";
      int i = s.ToInt32Ext();              
      Console.WriteLine(i);
      int j = EMClass.ToInt32Static(s);    
      Console.WriteLine(j);
      Console.ReadLine();
   }
}

The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable(Of T) types. To use the standard query operators, first bring them into scope with a using System.Linq directive. Then any type that implements IEnumerable(Of T) appears to have instance methods such as GroupBy, OrderBy, Average, and so on.

@2016-02-05 17:52:57

When you design an interface or class with a lot overloading methods, among them, one method is implemented with its own logic, the other overloading methods call the previous one, you create some extension methods to deal with the silly amount of duplication.

For example, IUnityContainer interface in Unity 1.2 has 42 members:

public interface IUnityContainer : IDisposable
{
    #region RegisterType overloads

    #region Generics overloads

    IUnityContainer RegisterType<T>(params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType<TFrom, TTo>(params InjectionMember[] injectionMembers) where TTo : TFrom;
    IUnityContainer RegisterType<TFrom, TTo>(LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers) where TTo : TFrom;
    IUnityContainer RegisterType<TFrom, TTo>(string name, params InjectionMember[] injectionMembers) where TTo : TFrom;
    IUnityContainer RegisterType<TFrom, TTo>(string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers) where TTo : TFrom;
    IUnityContainer RegisterType<T>(LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType<T>(string name, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType<T>(string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);

    #endregion

    #region Non-generics overloads

    IUnityContainer RegisterType(Type t, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type from, Type to, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type from, Type to, string name, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type from, Type to, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type t, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type t, string name, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type t, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
    IUnityContainer RegisterType(Type from, Type to, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);

    #endregion

    #endregion

    #region RegisterInstance overloads

    #region Generics overloads

    IUnityContainer RegisterInstance<TInterface>(TInterface instance);
    IUnityContainer RegisterInstance<TInterface>(TInterface instance, LifetimeManager lifetimeManager);
    IUnityContainer RegisterInstance<TInterface>(string name, TInterface instance);
    IUnityContainer RegisterInstance<TInterface>(string name, TInterface instance, LifetimeManager lifetimeManager);

    #endregion

    #region Non-generic overloads

    IUnityContainer RegisterInstance(Type t, object instance);
    IUnityContainer RegisterInstance(Type t, object instance, LifetimeManager lifetimeManager);
    IUnityContainer RegisterInstance(Type t, string name, object instance);
    IUnityContainer RegisterInstance(Type t, string name, object instance, LifetimeManager lifetime);

    #endregion

    #endregion

    #region Resolve overloads

    T Resolve<T>();
    T Resolve<T>(string name);
    object Resolve(Type t);
    object Resolve(Type t, string name);

    #endregion

    #region ResolveAll overloads

    IEnumerable<T> ResolveAll<T>();
    IEnumerable<object> ResolveAll(Type t);

    #endregion

    #region BuildUp overloads

    T BuildUp<T>(T existing);
    T BuildUp<T>(T existing, string name);
    object BuildUp(Type t, object existing);
    object BuildUp(Type t, object existing, string name);

    #endregion

    #region Teardown

    void Teardown(object o);

    #endregion
   
    #region Extension management and configuration

    IUnityContainer AddExtension(UnityContainerExtension extension);
    IUnityContainer AddNewExtension<TExtension>() where TExtension : UnityContainerExtension, new();

    TConfigurator Configure<TConfigurator>() where TConfigurator : IUnityContainerExtensionConfigurator;
    object Configure(Type configurationInterface);

    IUnityContainer RemoveAllExtensions();

    #endregion

    #region Child container management

    IUnityContainer CreateChildContainer();

    IUnityContainer Parent { get; }

    #endregion
}

@2016-02-05 18:04:04

The problem with the above interface is that all implementations of the interface has to implement all the methods. If you use extension methods here, than you can rewrite the interface like the following:

public interface IUnityContainer : IDisposable
{
  IUnityContainer RegisterType(Type from, Type to, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);

  IUnityContainer RegisterInstance(Type t, string name, object instance, LifetimeManager lifetime);

  object Resolve(Type t, string name);
  IEnumerable<object> ResolveAll(Type t);

  IUnityContainer AddExtension(UnityContainerExtension extension);
  IUnityContainer RemoveAllExtensions();

  object BuildUp(Type t, object existing, string name);

  void Teardown(object o);

  IUnityContainer Parent { get; }

  IUnityContainer CreateChildContainer();

  object Configure(Type configurationInterface);

}

The following code defines all extension methods:

public static class IUnityContainerExtentions
{
  public static IUnityContainer AddNewExtension<TExtension>(this IUnityContainer container) where TExtension : UnityContainerExtension, new()
  {
    return container.AddExtension(Activator.CreateInstance<TExtension>());
  }
  public static T BuildUp<T>(this IUnityContainer container, T existing)
  {
    return (T)container.BuildUp(typeof(T), existing, null);
  }
  public static object BuildUp(this IUnityContainer container, Type t, object existing)
  {
    return container.BuildUp(t, existing, null);
  }
  public static T BuildUp<T>(this IUnityContainer container, T existing, string name)
  {
    return (T)container.BuildUp(typeof(T), existing, name);
  }
  public static TConfigurator Configure<TConfigurator>(this IUnityContainer container) where TConfigurator : IUnityContainerExtensionConfigurator
  {
    return (TConfigurator)container.Configure(typeof(TConfigurator));
  }
  public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, TInterface instance)
  {
    return container.RegisterInstance(typeof(TInterface), null, instance, new ContainerControlledLifetimeManager());
  }
  public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, string name, TInterface instance)
  {
    return container.RegisterInstance(typeof(TInterface), name, instance, new ContainerControlledLifetimeManager());
  }
  public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, TInterface instance, LifetimeManager lifetimeManager)
  {
    return container.RegisterInstance(typeof(TInterface), null, instance, lifetimeManager);
  }
  public static IUnityContainer RegisterInstance(this IUnityContainer container, Type t, object instance)
  {
    return container.RegisterInstance(t, null, instance, new ContainerControlledLifetimeManager());
  }
  public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, string name, TInterface instance, LifetimeManager lifetimeManager)
  {
    return container.RegisterInstance(typeof(TInterface), name, instance, lifetimeManager);
  }
  public static IUnityContainer RegisterInstance(this IUnityContainer container, Type t, object instance, LifetimeManager lifetimeManager)
  {
    return container.RegisterInstance(t, null, instance, lifetimeManager);
  }
  public static IUnityContainer RegisterInstance(this IUnityContainer container, Type t, string name, object instance)
  {
    return container.RegisterInstance(t, name, instance, new ContainerControlledLifetimeManager());
  }
  public static IUnityContainer RegisterType<T>(this IUnityContainer container, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(typeof(T), null, null, null, injectionMembers);
  }
  public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, params InjectionMember[] injectionMembers) where TTo : TFrom
  {
    return container.RegisterType(typeof(TFrom), typeof(TTo), null, null, injectionMembers);
  }
  public static IUnityContainer RegisterType<T>(this IUnityContainer container, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(typeof(T), null, null, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers) where TTo : TFrom
  {
    return container.RegisterType(typeof(TFrom), typeof(TTo), null, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType<T>(this IUnityContainer container, string name, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(typeof(T), null, name, null, injectionMembers);
  }
  public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, string name, params InjectionMember[] injectionMembers) where TTo : TFrom
  {
    return container.RegisterType(typeof(TFrom), typeof(TTo), name, null, injectionMembers);
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type t, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(t, null, null, null, injectionMembers);
  }
  public static IUnityContainer RegisterType<T>(this IUnityContainer container, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(typeof(T), null, name, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers) where TTo : TFrom
  {
    return container.RegisterType(typeof(TFrom), typeof(TTo), name, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type t, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(t, null, null, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type t, string name, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(t, null, name, null, injectionMembers);
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type from, Type to, params InjectionMember[] injectionMembers)
  {
    container.RegisterType(from, to, null, null, injectionMembers);
    return container;
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type t, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(t, null, name, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type from, Type to, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(from, to, null, lifetimeManager, injectionMembers);
  }
  public static IUnityContainer RegisterType(this IUnityContainer container, Type from, Type to, string name, params InjectionMember[] injectionMembers)
  {
    return container.RegisterType(from, to, name, null, injectionMembers);
  }
  public static T Resolve<T>(this IUnityContainer container)
  {
    return (T)container.Resolve(typeof(T));
  }
  public static T Resolve<T>(this IUnityContainer container, string name)
  {
    return (T)container.Resolve(typeof(T), name);
  }
  public static object Resolve(this IUnityContainer container, Type t)
  {
    return container.Resolve(t, null);
  }
  public static IEnumerable<T> ResolveAll<T>(this IUnityContainer container)
  {
    //return new <ResolveAll>d__0<T>(-2) { <>4__this = this };
    //This implementation requires more effort than I am willing to give (6hours till my holiday!)
  }
}

Comments

You must Sign In to comment on this topic.


© 2024 Digcode.com