Axd*_*der 5 .net c# dependency-injection inversion-of-control
我有一个服务,我希望能够根据控制反转原理创建,所以我创建了一个接口和一个服务类.
public interface IMyService
{
void DoSomeThing1();
void DoSomeThing2();
void DoSomeThing3();
string GetSomething();
}
public class MyService : IMyService
{
int _initialValue;
//...
public MyService(int initialValue)
{
_initialValue = initialValue;
}
public void DoSomeThing1()
{
//Do something with _initialValue
//...
}
public void DoSomeThing2()
{
//Do something with _initialValue
//...
}
public void DoSomeThing3()
{
//Do something with _initialValue
//...
}
public string GetSomething()
{
//Get something with _initialValue
//...
}
}
Run Code Online (Sandbox Code Playgroud)
以Unity为例,我可以设置IoC.
public static class MyServiceIoc
{
public static readonly IUnityContainer Container;
static ServiceIoc()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IMyService, MyService>();
Container = container;
}
}
Run Code Online (Sandbox Code Playgroud)
问题是构造函数参数.我可以使用ParameterOverride之类的
var service = MyServiceIoc.Container.Resolve<IMyService>(new ParameterOverrides
{
{"initialValue", 42}
});
Run Code Online (Sandbox Code Playgroud)
但我不想使用输入错误的参数.如果有人更改构造函数参数名称或添加一个参数怎么办?他不会在完成时被警告,也许没有人会检测到它,但最终用户.也许程序员改变了IoC设置的测试,但忘记了它的"发布"用法,然后即使是具有100%代码覆盖率的代码库也不会检测到运行时错误.
可以在接口和服务中添加Init函数,但是服务的用户必须理解这一点,并且每次获得服务实例时都要记得调用init函数.该服务变得不那么自我解释,并且对于不正确的使用是开放的.如果方法不依赖于它们的调用顺序,那我是最好的.
让它更安全的一种方法是在Ioc上有一个Create-function.
public static class MyServiceIoc
{
//...
public IMyService CreateService(int initialValue)
{
var service = Container.Resolve<IMyService>();
service.Init(initialValue);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您只查看服务及其界面,上述问题仍然适用.
有没有人有这个问题的强大解决方案?如何使用IoC以安全的方式将初始值传递给我的服务?
DI 容器是基于反射的,并且基本上是弱类型的。这个问题比原始依赖关系要广泛得多——它无处不在。
一旦您执行了类似以下操作,您就已经失去了编译时安全性:
IUnityContainer container = new UnityContainer();
container.RegisterType<IMyService, MyService>();
var service = container.Resolve<IMyService>(new ParameterOverrides
{
{"initialValue", 42}
});
Run Code Online (Sandbox Code Playgroud)
问题是您可以删除第二条语句,代码仍然可以编译,但现在它不再起作用:
IUnityContainer container = new UnityContainer();
var service = container.Resolve<IMyService>(new ParameterOverrides
{
{"initialValue", 42}
});
Run Code Online (Sandbox Code Playgroud)
请注意,编译时安全性的缺乏与具体依赖关系无关,而是与涉及 DI 容器这一事实有关。
这也不是 Unity 的问题;它适用于所有 DI 容器。
在某些情况下,DI 容器可能有意义,但在大多数情况下,纯 DI是一种更简单、更安全的替代方案:
IMyService service = new MyService(42);
Run Code Online (Sandbox Code Playgroud)
在这里,如果其他人在您视线移开时更改了 API,您将收到编译器错误。这很好:编译器错误比运行时错误为您提供更直接的反馈。
顺便说一句,当您传递原始依赖项并无形地将其转换为具体依赖项时,您会使客户更难以理解正在发生的事情。
我建议这样设计:
public class MyService : IMyService
{
AnotherClass _anotherObject;
// ...
public MyService(AnotherClass anotherObject)
{
_anotherObject = anotherObject;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
使用 Pure DI 组合起来仍然很简单且类型安全:
IMyService service = new MyService(new AnotherClass(42));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3978 次 |
| 最近记录: |