我正在研究统一容器,并快速询问如何将一个类的构造解决为多个不同的接口实现。
这是我的代码:
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);
}
}
}
并注册/解决
// Create the container
var container = new UnityContainer();
// registration
container.RegisterType<IRenderer, GlRenderer>("GL");
container.RegisterType<IRenderer, Dx11Renderer>("DX11");
Canvas canvas = container.Resolve<Canvas>("GL");
这会抛出&#34; ResolutionFailedException&#34;所以我必须错误地使用它。
有人可以解释这是不好的做法,或者我是如何做到的。
由于
更新:
所以我所做的就是在每种类型的依赖项中注册Canvas两次,如下所示:
// 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");
这对我有用!
答案 0 :(得分:6)
问题是您正在使用名称“GL”解析Canvas,但是您没有以这种方式注册Canvas。 Unity不会将名称传播到依赖项解析,因此在解析IRenderer时不会使用名称“GL”。
有几种方法可以解决这个问题:Resolving named dependencies with Unity
您的问题是这是一种不好的做法,还是您如何取得相同的结果。根据我的经验,尝试注册和解析同一界面的多个实例通常会导致代码混乱。另一种方法是使用Factory模式创建Canvas实例。
您是否需要使用容器来解析Canvas?如果你没有理由,你可以简单地解决你的IRenderer并自己新建一个画布:
new Canvas(container.Resolve<IRenderer>("GL"));
请记住,Unity只是一种工具,如果它似乎无法满足您的需求,您可能需要一种不同的工具。
答案 1 :(得分:1)
有一种方法可以在启动时在画布中注入正确的渲染器。如果您在启动时知道渲染方法,则只能注册正确的渲染器:
var container = new UnityContainer();
container.RegisterType<ICanvas, Canvas>();
if (CheckIfItIsDx11)
{
container.RegisterType<IRenderer, Dx11Renderer>();
}
else
{
container.RegisterType<IRenderer, GlRenderer>();
}
当您想要解析画布时,只需使用:
var canvas = container.Resolve<ICanvas>();
如果您在启动时不知道渲染器,则可以使用。像这样:
container.RegisterType<IRenderer, Dx11Renderer>("DX11");
container.RegisterType<IRenderer, GlRenderer>("GL");
var renderer = container.Resolve<IRenderer>("DX11");
var canvas = container.Resolve<ICanvas>(new ParameterOverride("renderer", renderer));
Canvas现在注入了正确的渲染器。画布可以使用渲染器界面,如下所示:
internal interface ICanvas
{
void Draw();
}
public class Canvas : ICanvas
{
private readonly IRenderer _renderer;
private readonly List<Circle> _circles = new List<Circle>();
private readonly List<Square> _squares = new List<Square>();
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");
}
}
}
希望这会有所帮助。