- add registration implementations

pull/32/head
Simon Gockner 7 years ago
parent 31419c65ce
commit 706ca44b34
  1. 65
      LightweightIocContainer/Registrations/DefaultRegistration.cs
  2. 38
      LightweightIocContainer/Registrations/RegistrationFactory.cs
  3. 128
      LightweightIocContainer/Registrations/TypedFactoryRegistration.cs

@ -0,0 +1,65 @@
// Author: simon.gockner
// Created: 2019-05-20
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations
{
/// <summary>
/// The default registration that is used to register a Type for the Interface it implements
/// </summary>
/// <typeparam name="TInterface">The registered Interface</typeparam>
public class DefaultRegistration<TInterface> : IDefaultRegistration<TInterface>
{
public DefaultRegistration(Type interfaceType, Type implementationType, Lifestyle lifestyle)
{
InterfaceType = interfaceType;
ImplementationType = implementationType;
Lifestyle = lifestyle;
Name = $"{InterfaceType.Name}, {ImplementationType.Name}, Lifestyle: {Lifestyle.ToString()}";
}
/// <summary>
/// The name of the <see cref="DefaultRegistration{TInterface}"/>
/// </summary>
public string Name { get; }
/// <summary>
/// The Type of the Interface that is registered with this <see cref="DefaultRegistration{TInterface}"/>
/// </summary>
public Type InterfaceType { get; }
/// <summary>
/// The Type that implements the <see cref="InterfaceType"/> that is registered with this <see cref="DefaultRegistration{TInterface}"/>
/// </summary>
public Type ImplementationType { get; }
/// <summary>
/// The Lifestyle of Instances that are created with this <see cref="DefaultRegistration{TInterface}"/>
/// </summary>
public Lifestyle Lifestyle { get; }
/// <summary>
/// This action is invoked when an instance of this type is created.
/// <para>Can be set in the <see cref="IInjectorInstaller"/> by calling <see cref="OnCreate"/></para>
/// </summary>
public Action<TInterface> OnCreateAction { get; private set; }
/// <summary>
/// Pass an action that will be invoked when an instance of this type is created
/// </summary>
/// <param name="action">The action</param>
/// <returns>The current instance of this <see cref="IDefaultRegistration{TInterface}"/></returns>
public IDefaultRegistration<TInterface> OnCreate(Action<TInterface> action)
{
OnCreateAction = action;
return this;
}
}
}

@ -0,0 +1,38 @@
// Author: simon.gockner
// Created: 2019-05-20
// Copyright(c) 2019 SimonG. All Rights Reserved.
using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations
{
/// <summary>
/// A factory to register interfaces and factories in an <see cref="IInjectorInstaller"/> and create the needed <see cref="IRegistrationBase"/>s
/// </summary>
public static class RegistrationFactory
{
/// <summary>
/// Register an Interface with a Type that implements it and create a <see cref="IDefaultRegistration{TInterface}"/>
/// </summary>
/// <typeparam name="TInterface">The Interface to register</typeparam>
/// <typeparam name="TImplementation">The Type that implements the <see cref="TInterface"/></typeparam>
/// <param name="lifestyle">The <see cref="Lifestyle"/> for this <see cref="IDefaultRegistration{TInterface}"/></param>
/// <returns>A new created <see cref="IDefaultRegistration{TInterface}"/> with the given parameters</returns>
public static IDefaultRegistration<TInterface> Register<TInterface, TImplementation>(Lifestyle lifestyle = Lifestyle.Transient) where TImplementation : TInterface
{
return new DefaultRegistration<TInterface>(typeof(TInterface), typeof(TImplementation), lifestyle);
}
/// <summary>
/// Register an Interface as an abstract typed factory and create a <see cref="ITypedFactoryRegistration{TFactory}"/>
/// </summary>
/// <typeparam name="TFactory">The abstract typed factory to register</typeparam>
/// <param name="container">The current <see cref="IInjectorContainer"/></param>
/// <returns>A new created <see cref="ITypedFactoryRegistration{TFactory}"/> with the given parameters</returns>
public static ITypedFactoryRegistration<TFactory> RegisterFactory<TFactory>(IInjectorContainer container) //TODO: Find a nicer way to inject the container into `TypedFactoryRegistration`
{
return new TypedFactoryRegistration<TFactory>(typeof(TFactory), container);
}
}
}

@ -0,0 +1,128 @@
// Author: simon.gockner
// Created: 2019-05-20
// Copyright(c) 2019 SimonG. All Rights Reserved.
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Factories;
using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Factories;
using LightweightIocContainer.Interfaces.Registrations;
namespace LightweightIocContainer.Registrations
{
/// <summary>
/// The registration that is used to register an abstract typed factory
/// </summary>
/// <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
public class TypedFactoryRegistration<TFactory> : ITypedFactoryRegistration<TFactory>
{
private readonly IInjectorContainer _container;
public TypedFactoryRegistration(Type factoryType, IInjectorContainer container)
{
_container = container;
InterfaceType = factoryType;
Name = $"{InterfaceType.Name}";
CreateFactory();
}
/// <summary>
/// The name of the <see cref="TypedFactoryRegistration{TFactory}"/>
/// </summary>
public string Name { get; }
/// <summary>
/// The Type of the abstract typed factory that is registered with this <see cref="TypedFactoryRegistration{TFactory}"/>
/// </summary>
public Type InterfaceType { get; }
/// <summary>
/// The class that contains the implemented abstract factory of this <see cref="TypedFactoryRegistration{TFactory}"/>
/// </summary>
public ITypedFactory<TFactory> Factory { get; private set; }
/// <summary>
/// Creates the factory from the given abstract factory type
/// </summary>
/// <exception cref="InvalidFactoryRegistrationException">Factory registration is invalid</exception>
private void CreateFactory()
{
var createMethods = InterfaceType.GetMethods().Where(m => m.ReturnType != typeof(void)).ToList();
if (!createMethods.Any())
throw new InvalidFactoryRegistrationException($"Factory {Name} has no create methods.");
Type type = typeof(TypedFactory<>);
Type factory = type.MakeGenericType(InterfaceType);
Factory = (ITypedFactory<TFactory>) Activator.CreateInstance(factory);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Factory"), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Factory");
TypeBuilder typeBuilder = moduleBuilder.DefineType($"TypedFactory.{InterfaceType.Name}");
typeBuilder.AddInterfaceImplementation(InterfaceType);
//add `private readonly IInjectorContainer _container` field
FieldBuilder containerFieldBuilder = typeBuilder.DefineField("_container", typeof(IInjectorContainer), FieldAttributes.Private | FieldAttributes.InitOnly);
//add ctor
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] {typeof(IInjectorContainer)});
var constructorGenerator = constructorBuilder.GetILGenerator();
constructorGenerator.Emit(OpCodes.Ldarg_0);
constructorGenerator.Emit(OpCodes.Ldarg_1);
constructorGenerator.Emit(OpCodes.Stfld, containerFieldBuilder); //set `_container` field
constructorGenerator.Emit(OpCodes.Ret);
foreach (var createMethod in createMethods)
{
//create a method that looks like this
//public `createMethod.ReturnType` Create(`createMethod.GetParameters()`)
//{
// return IInjectorContainer.Resolve(`createMethod.ReturnType`, params);
//}
var args = createMethod.GetParameters();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(createMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
createMethod.ReturnType, (from arg in args select arg.ParameterType).ToArray());
typeBuilder.DefineMethodOverride(methodBuilder, createMethod);
var generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, containerFieldBuilder);
generator.Emit(OpCodes.Ldtoken, createMethod.ReturnType);
if (args.Any())
{
generator.Emit(OpCodes.Ldc_I4_S, args.Length + 1);
generator.Emit(OpCodes.Newarr, typeof(object));
for (int i = 0; i < args.Length; i++)
{
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_S, i);
generator.Emit(OpCodes.Ldarg_S, i + 1);
generator.Emit(OpCodes.Stelem_Ref);
}
}
else
{
generator.Emit(OpCodes.Ldc_I4_0);
}
generator.EmitCall(OpCodes.Callvirt, typeof(IInjectorContainer).GetMethod(nameof(IInjectorContainer.Resolve), new[] { typeof(object), typeof(object)}), null);
generator.Emit(OpCodes.Ret);
}
Factory.Factory = (TFactory) Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType(), _container);
}
}
}
Loading…
Cancel
Save