Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity Container Multiple Implementations of same interface

I'm studying up on the unity containers and have a quick question on how to resolve a class's construction to multiple different implementations of an interface.

Here's my code:

public interface IRenderer
{
    void DrawSquare(Square square);
    void DrawCircle(Circle circle);
}

public interface IShape
{
    void Draw(IRenderer renderer);
}

public class Dx11Renderer : IRenderer
{
    public void DrawSquare(Square square)
    {
    }

    public void DrawCircle(Circle circle)
    {
    }
}

public class GlRenderer : IRenderer
{
    public void DrawSquare(Square square)
    {
    }

    public void DrawCircle(Circle circle)
    {
    }
}

public class Circle : IShape
{
    public void Draw(IRenderer renderer) { renderer.DrawCircle(this); }   
}

public class Square
{
    public void Draw(IRenderer renderer) { renderer.DrawSquare(this); }   
}

public class Canvas
{
    private readonly IRenderer _renderer;

    private List<Circle> _circles = new List<Circle>();
    private List<Square> _squares = new List<Square>(); 

    public Canvas(IRenderer renderer)
    {
        _renderer = renderer;
    }

    public void Draw()
    {
        foreach (Circle c in _circles)
        {
            c.Draw(_renderer);
        }

        foreach (Square s in _squares)
        {
            s.Draw(_renderer);
        }
    }
}

and to register/resolve

        // Create the container
        var container = new UnityContainer();

        // registration

        container.RegisterType<IRenderer, GlRenderer>("GL");
        container.RegisterType<IRenderer, Dx11Renderer>("DX11");

        Canvas canvas = container.Resolve<Canvas>("GL");

This throws a "ResolutionFailedException" so I must be using this incorrectly.

Can someone explain if this is bad practice, or how I can achieve this.

Thanks

UPDATE:

So what I have done is registered Canvas twice with each type of dependencies like so:

// Canvas with an OpenGL Renderer
container.RegisterType<Canvas>("GLCanvas", new InjectionConstructor(new ResolvedParameter<IRenderer>("GL")));
// Canvas with a DirectX Renderer
container.RegisterType<Canvas>("DXCanvas", new InjectionConstructor(new ResolvedParameter<IRenderer>("DX11")));

Canvas canvas = container.Resolve<Canvas>("GLCanvas");

This works well for me!

like image 598
rocklobster Avatar asked May 15 '14 04:05

rocklobster


People also ask

Can multiple classes implement the same interface C#?

C# allows that a single class can implement multiple interfaces at a time, and also define methods and variables in that interface.

What is Unity IoC container?

The Unity Container (Unity) is a full featured, extensible dependency injection container. It facilitates building loosely coupled applications and provides developers with the following advantages: Simplified object creation, especially for hierarchical object structures and dependencies.

What is unity container Microsoft?

Unity container is an open source IoC container for . NET applications supported by Microsoft. It is a lightweight and extensible IoC container. The source code for Unity container is available at https://github.com/unitycontainer/unity.


1 Answers

The problem is that you are resolving Canvas with the name "GL", but you have not registered Canvas in that way. Unity doesn't propagate the name to dependency resolution, so it won't use the name "GL" when resolving IRenderer.

There are several options to solve this already answered: Resolving named dependencies with Unity

Your question is whether this is a bad practice, or how you can achieve the same results. In my experience, trying to register and resolve multiple instances of the same interface usually leads to messy code. One alternative would be to use the Factory pattern to create instances of Canvas.

Do you need to use your container to resolve Canvas? If you don't have a reason not to, you could simply Resolve your IRenderer and new up a Canvas yourself:

new Canvas(container.Resolve<IRenderer>("GL"));

Remember that Unity is just a tool, if it doesn't seem to be capable of doing what you need, you may need a different kind of tool.

like image 55
Thomas Femiani Avatar answered Oct 20 '22 04:10

Thomas Femiani