-
Notifications
You must be signed in to change notification settings - Fork 7
NCop IoC
Sagi edited this page Jul 9, 2017
·
14 revisions
NCop IoC is based on Funq
- which was adopted because of its excellent performance and memory characteristics.
NCop's version of Funq has been enhanced with Expression-based Auto-wiring using the System.Linq.Expressions
namespace, resulting in a compiled factory per registration, which means no reflective invocations at all.
If you so wish, you can still select to use your favourite IoC by creating an INCopDependencyContainerAdapter
adapter.
See below for examples of adapters for popular IoC's.
Using another IoC container
public interface INCopDependencyContainerAdapter : INCopDependencyContainer, INCopRegistry
{
}
public interface INCopRegistry
{
void Register(Type concreteType, Type serviceType, string name = null);
}
public interface INCopDependencyContainer : INCopDependencyResolver, ICanCreateChildContainer
{
}
public interface INCopDependencyResolver : IDisposable
{
void Configure();
TService Resolve<TService>();
TService TryResolve<TService>();
TService ResolveNamed<TService>(string name);
TService TryResolveNamed<TService>(string name);
}
public interface ICanCreateChildContainer
{
INCopDependencyContainer CreateChildContainer();
}
Use structureMap
public class StructureMapAdapter : INCopDependencyContainerAdapter
{
private readonly IContainer container = null;
public StructureMapAdapter()
: this(ObjectFactory.Container) {
}
public StructureMapAdapter(IContainer container) {
this.container = container;
}
public void Configure() { }
public TService Resolve<TService>() {
return container.GetInstance<TService>();
}
public TService TryResolve<TService>() {
return container.TryGetInstance<TService>();
}
public TService ResolveNamed<TService>(string name) {
return container.GetInstance<TService>(name);
}
public TService TryResolveNamed<TService>(string name) {
return container.TryGetInstance<TService>(name);
}
public void Dispose() {
container.Dispose();
}
public INCopDependencyContainer CreateChildContainer() {
return new StructureMapAdapter(container.GetNestedContainer());
}
public void Register(TypeMap typeMap, ITypeMapCollection dependencies = null) {
container.Configure(x => {
var use = x.For(typeMap.ServiceType)
.Use(typeMap.ConcreteType);
if (typeMap.Name.IsNotNullOrEmpty()) {
use.Named(typeMap.Name);
}
if (dependencies.IsNotNullOrEmpty()) {
x.For(typeMap.ServiceType).Use("composite", BuildExpression(typeMap, dependencies));
}
});
}
private Func<IContext, object> BuildExpression(TypeMap typeMap, ITypeMapCollection dependencies) {
var contextParameter = Expression.Parameter(typeof(IContext), "context");
var @params = dependencies.ToArray(d => d.ServiceType);
var ctorInfo = typeMap.ConcreteType.GetConstructor(@params);
var genericMethodInfo = typeof(IContext).GetMethods().First(method => {
return method.Name.Equals("GetInstance") &&
method.IsGenericMethodDefinition &&
method.GetParameters().Length == 1;
});
var getInstanceCallExpressions = dependencies.Select(dependency => {
var nameParam = Expression.Constant(dependency.Name, typeof(string));
var methodInfo = genericMethodInfo.MakeGenericMethod(new[] { dependency.ServiceType });
return Expression.Call(contextParameter, methodInfo, new[] { nameParam });
});
var lambda = Expression.Lambda<Func<IContext, object>>(
Expression.New(ctorInfo, getInstanceCallExpressions),
contextParameter);
return lambda.Compile();
}
}
In order to order NCop to use StructureMap
as the IoC container you will have to create CompositeRuntimeSettings
and set its DependencyContainerAdapter
property to the StructureMapAdapter
instance:
using System;
using NCop.Composite.Framework;
using NCop.Composite.Runtime;
using NCop.Mixins.Framework;
using StructureMap;
class Program
{
static void Main(string[] args) {
IDeveloper developer = null;
var container = new CompositeContainer(new CompositeRuntimeSettings {
DependencyContainerAdapter = new StructureMapAdapter()
});
container.Configure();
developer = container.Resolve<IDeveloper>();
developer.Code();
}
}