Unity Container多个相同接口的实现

我正在研究统一容器,并且有一个关于如何将类的构造解析为接口的多个不同实现的快速问题。

这是我的代码:

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 _circles = new List(); private List _squares = new List(); 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); } } } 

并注册/解决

  // Create the container var container = new UnityContainer(); // registration container.RegisterType("GL"); container.RegisterType("DX11"); Canvas canvas = container.Resolve("GL"); 

这会抛出“ResolutionFailedException”,所以我必须错误地使用它。

有人可以解释这是不好的做法,或者我是如何做到这一点的。

谢谢

更新:

所以我所做的是在每种类型的依赖项中注册Canvas两次,如下所示:

 // Canvas with an OpenGL Renderer container.RegisterType("GLCanvas", new InjectionConstructor(new ResolvedParameter("GL"))); // Canvas with a DirectX Renderer container.RegisterType("DXCanvas", new InjectionConstructor(new ResolvedParameter("DX11"))); Canvas canvas = container.Resolve("GLCanvas"); 

这对我很有用!

问题是您正在使用名称“GL”解析Canvas,但是您没有以这种方式注册Canvas。 Unity不会将名称传播到依赖项解析,因此在解析IRenderer时不会使用名称“GL”。

有几种方法可以解决这个问题:已经解决过: 使用Unity解决命名的依赖关系

您的问题是这是一种不好的做法,还是如何实现相同的结果。 根据我的经验,尝试注册和解析同一界面的多个实例通常会导致代码混乱。 另一种方法是使用Factory模式创建Canvas实例。

您是否需要使用容器来解析Canvas? 如果你没有理由不这样做,你可以简单地解决你的IRenderer并自己新建一个canvas:

 new Canvas(container.Resolve("GL")); 

请记住,Unity只是一种工具,如果它似乎无法满足您的需求,您可能需要一种不同的工具。

有一种方法可以在启动时在canvas中注入正确的渲染器。 如果您在启动时知道渲染方法,则只能注册正确的渲染器,如下所示:

 var container = new UnityContainer(); container.RegisterType(); if (CheckIfItIsDx11) { container.RegisterType(); } else { container.RegisterType(); } 

当你想要解析canvas时,只需使用:

 var canvas = container.Resolve(); 

如果你不知道启动时的渲染器有一种方法。 像这样:

 container.RegisterType("DX11"); container.RegisterType("GL"); var renderer = container.Resolve("DX11"); var canvas = container.Resolve(new ParameterOverride("renderer", renderer)); 

Canvas现在注入了正确的渲染器。 canvas可以像这样使用渲染器界面:

 internal interface ICanvas { void Draw(); } public class Canvas : ICanvas { private readonly IRenderer _renderer; private readonly List _circles = new List(); private readonly List _squares = new List(); public Canvas(IRenderer renderer) { _renderer = renderer; } public void Draw() { foreach (var circle in _circles) { _renderer.Draw(circle); } foreach (var square in _squares) { _renderer.Draw(square); } } } 

渲染器也不应该绘制形状。 形状负责绘制自己。 这样您就可以将代码保存在同一位置。 如果继续添加形状,渲染器文件会变得很大。 如果要更改代码,则需要搜索某些形状。 现在一切都在正确的地方。 代码现在看起来像这样:

 public interface IRenderer { void Draw(IShape shape); } public interface IShape { void Draw(IRenderer renderer); } public class Dx11Renderer : IRenderer { public void Draw(IShape shape) { shape.Draw(this); } } public class GlRenderer : IRenderer { public void Draw(IShape shape) { shape.Draw(this); } } public class Circle : IShape { public void Draw(IRenderer renderer) { if (renderer.GetType() == typeof(Dx11Renderer)) { Console.WriteLine("Draw circle with DX11"); } if (renderer.GetType() == typeof(GlRenderer)) { Console.WriteLine("Draw circle with GL"); } } } public class Square : IShape { public void Draw(IRenderer renderer) { if (renderer.GetType() == typeof(Dx11Renderer)) { Console.WriteLine("Draw square with DX11"); } if (renderer.GetType() == typeof(GlRenderer)) { Console.WriteLine("Draw square with GL"); } } } 

希望这会有所帮助。