Skip to content
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();
    }
}