Skip to content

Down Casting Composites

Sagi edited this page Apr 9, 2015 · 20 revisions

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

[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 (IDeveloper developer, IMusician musician)
    {
        this.musician = musician;
        this.developer = developer;
    }
}

NCop will register a new entry in the IoC container for the interface and the implementation IPerson -> PersonImpl, But also for each mixin and implementation.
IDeveloper -> CSharpDeveloperMixin and IMusician -> GuitarPlayerMixin.
In order to register different implementations for the same interface you will need to order NCop to register a named entry.
Lets say that we want to create two different composites for IDeveloper.

[TransientComposite]
[Mixins(typeof(JavaScriptDeveloperMixin))]
public interface IJavaScriptDeveloper : IDeveloper
{
}

[TransientComposite]
[Mixins(typeof(CSharpDeveloperMixin))]
public interface ICSharpDeveloper : IDeveloper
{
}

public class JavaScriptDeveloperMixin : IDeveloper
{
    public void Code() {
        Console.WriteLine("JavaScript coding");
    }
}

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

You'll have to order NCop to do two things:

  1. Down cast ICSharpDeveloper and IJavaScriptDeveloper to IDeveloper by applying the As parameter to the TransientCompositeAttributeattribute.
  2. Name each of the composites by applying the NamedAttribute attribute.
[Named("JavaScript")]
[Mixins(typeof(JavaScriptDeveloperMixin))]
[TransientComposite(As = typeof(IDeveloper))]
public interface IJavaScriptDeveloper : IDeveloper
{
}

[Named("C#")]
[Mixins(typeof(CSharpDeveloperMixin))]
[TransientComposite(As = typeof(IDeveloper))]
public interface ICSharpDeveloper : IDeveloper
{
}

Now we can resolve both types using the ResolveNamed function of the IoC

class Program
{
    static void Main(string[] args) {
        IDeveloper developer = null;
        var container = new CompositeContainer();

        container.Configure();
        developer = container.ResolveNamed<IDeveloper>("C#");
        developer.Code();
        developer = container.ResolveNamed<IDeveloper>("JavaScript");
        developer.Code();
    }
}

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

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

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

    public class JavaScriptDeveloperMixin : IDeveloper
    {
        public void Code() {
            Console.WriteLine("JavaScript coding");
        }
    }

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

    [Named("JavaScript")]
    [Mixins(typeof(JavaScriptDeveloperMixin))]
    [TransientComposite(As = typeof(IDeveloper))]
    public interface IJavaScriptDeveloper : IDeveloper
    {
    }

    [Named("C#")]
    [Mixins(typeof(CSharpDeveloperMixin))]
    [TransientComposite(As = typeof(IDeveloper))]
    public interface ICSharpDeveloper : IDeveloper
    {
    }

    class Program
    {
        static void Main(string[] args) {
            IDeveloper developer = null;
            var container = new CompositeContainer();

            container.Configure();
            developer = container.ResolveNamed<IDeveloper>("C#");
            developer.Code();
            developer = container.ResolveNamed<IDeveloper>("JavaScript");
            developer.Code();
        }
    }
}