Skip to content
Sagi edited this page Oct 30, 2015 · 18 revisions

When NCop crafts the proxy object it builds it with a specific constructor which accepts all mixin types.

public class CSharpDeveloperMixin : IDeveloper
{
    public void Code() {
        Console.WriteLine("C# coding");
    }
}

public class GuitarPlayerMixin : IMusician
{
    public void Play() {
        Console.WriteLine("I am playing C# accord with Fender Telecaster");
    }
}

[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin), typeof(GuitarPlayerMixin))]
public interface IPerson : IDeveloper, IMusician
{
}

/// Proxy
public class PersonProxyImpl : IPerson
{
    private readonly IMusician musician = null;
    private readonly IDeveloper developer = null;

    public PersonProxyImpl() {
        this.musician = new GuitarPlayerMixin();
        this.developer = new CSharpDeveloperMixin();
    }
}

For each mixin/implementation NCop will register also a new entry in the IoC container IDeveloper -> CSharpDeveloperMixin.
The entry is basically a compiled factory for the mixin:

Func<IMusician> musicianFactory = () => new GuitarPlayerMixin();
Func<IDeveloper> developerFactory = () => new CSharpDeveloperMixin();

Each mixin is instantiated using its default parameterless constructor.
NCop uses the IoC container in order to inject the dependent mixins to the composite.

var musician = container.Resolve<IMusician>();
var developer = container.Resolve<IDeveloper>();
var person = container.Resolve<IPerson>(developer, musician);

By choosing the injection pattern and not creating a direct instantiation of the mixin within the composite like this:

/// Proxy
public class PersonProxyImpl : IPerson
{
    private readonly IMusician musician = null;
    private readonly IDeveloper developer = null;

    public PersonProxyImpl() {
        this.musician = new GuitarPlayerMixin();
        this.developer = new CSharpDeveloperMixin();
    }
}

NCop supports the possibility to register complex object graphs for each mixin.

Lets say that the CSharpDeveloperMixin is dependent upon other type.

public interface ICSharpLanguageVersion
{
    int Version { get; }
}

public class CSharp5LanguageVersion : ICSharpLanguageVersion
{
    public int Version {
        get {
            return 5;
        }
    }
}

public class CSharpDeveloperMixin : IDeveloper
{
    private readonly ICSharpLanguageVersion languageVersion = null;

    public CSharpDeveloperMixin(ICSharpLanguageVersion languageVersion) {
        this.languageVersion = languageVersion;
    }

    public void Code() {
        Console.WriteLine("C# {0} coding", languageVersion.Version);
    }
}

Current version of NCop does not supports registration of complex object graphs, however you will be able to overcome it by doing couple of things:

  • Instantiate new INCopDependencyContainerAdapter implemented by an adapter to your favorite IoC Container.
using StructureMap;

var smContainer = ObjectFactory.Container;
var container = new CompositeContainer(new CompositeRuntimeSettings {
    DependencyContainerAdapter = new StructureMapAdapter(smContainer)
});
  • Register the dependencies of the object graph properly using your container:
smContainer.Configure(x => {
    x.For<ICSharpLanguageVersion>().Use<CSharp5LanguageVersion>();
});

The end result of the IPerson resolution would be:

using System;
using StructureMap;
using NCop.Composite.Framework;

class Program
{
    static void Main(string[] args) {
        IPerson person = null;
        var smContainer = ObjectFactory.Container;
        var container = new CompositeContainer(new CompositeRuntimeSettings {
            DependencyContainerAdapter = new StructureMapAdapter(smContainer)
        });

        smContainer.Configure(x => {
            x.For<ICSharpLanguageVersion>().Use<CSharp5LanguageVersion>();
        });

        container.Configure();
        person = container.Resolve<IPerson>();
        person.Code();
    }
}

The expected output should be
"C# 5 coding"
Your end result of the code should be similar to this:

using System;
using NCop.Composite.Framework;
using NCop.Composite.Runtime;
using NCop.Mixins.Framework;
using StructureMap;

namespace NCop.Samples
{
    public interface IDeveloper
    {
        void Code();
    }

    public interface IMusician
    {
        void Play();
    }

    public interface ICSharpLanguageVersion
    {
        int Version { get; }
    }

    [TransientComposite]
    [Mixins(typeof(CSharpDeveloperMixin), typeof(GuitarPlayerMixin))]
    public interface IPerson : IDeveloper, IMusician
    {
    }

    public class CSharp5LanguageVersion : ICSharpLanguageVersion
    {
        public int Version {
            get {
                return 5;
            }
        }
    }

    public class GuitarPlayerMixin : IMusician
    {
        public void Play() {
            Console.WriteLine("Playing C# accord with Fender Telecaster");
        }
    }

    public class CSharpDeveloperMixin : IDeveloper
    {
        private readonly ICSharpLanguageVersion languageVersion = null;

        public CSharpDeveloperMixin(ICSharpLanguageVersion languageVersion) {
            this.languageVersion = languageVersion;
        }

        public void Code() {
            Console.WriteLine("C# {0} coding", languageVersion.Version);
        }
    }

    class Program
    {
        static void Main(string[] args) {
            IPerson person = null;
            var smContainer = ObjectFactory.Container;
            var container = new CompositeContainer(new CompositeRuntimeSettings {
                DependencyContainerAdapter = new StructureMapAdapter(smContainer)
            });

            smContainer.Configure(x => {
                x.For<ICSharpLanguageVersion>().Use<CSharp5LanguageVersion>();
            });

            container.Configure();
            person = container.Resolve<IPerson>();
            person.Code();
        }
    }
}