gpt4 book ai didi

c# - IoC、依赖注入(inject)和构造函数参数

转载 作者:太空狗 更新时间:2023-10-29 23:21:30 27 4
gpt4 key购买 nike

我希望能够根据控制反转原则创建一个服务,因此我创建了一个接口(interface)和一个服务类。

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
//...
}
}

例如使用 Unity,我可以设置我的 IoC。

public static class MyServiceIoc
{
public static readonly IUnityContainer Container;

static ServiceIoc()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IMyService, MyService>();
Container = container;
}
}

问题是构造函数参数。我可以使用像

这样的 ParameterOverride
var service = MyServiceIoc.Container.Resolve<IMyService>(new ParameterOverrides
{
{"initialValue", 42}
});

但我不想使用松散类型的参数。如果有人更改构造函数参数名称或添加一个参数怎么办?他不会在完成时收到警告,也许除了最终用户之外没有人会检测到它。也许程序员为测试更改了 IoC 设置,但忘记了“发布”用法,那么即使是具有 100% 代码覆盖率的代码库也无法检测到运行时错误。

可以向接口(interface)和服务添加一个 Init 函数,但是服务的用户必须理解这一点,并记住在每次获得服务实例时调用 init 函数。该服务变得不那么 self 解释,并且对不正确的使用开放。如果方法不依赖于它们被调用的顺序,那是最好的。

使它更安全的一种方法是在 Ioc 上有一个创建函数。

public static class MyServiceIoc
{
//...
public IMyService CreateService(int initialValue)
{
var service = Container.Resolve<IMyService>();
service.Init(initialValue);

}
}

但如果您只看服务及其接口(interface),上述问题仍然存在。

有没有人对这个问题有可靠的解决方案?如何仍使用 IoC 以安全的方式将初始值传递给我的服务?

最佳答案

DI 容器是基于反射的,并且基本上是弱类型的。问题比 Primitive Dependencies 广泛得多- 它无处不在。

一旦你做了类似下面的事情,你就已经失去了编译时的安全性:

IUnityContainer container = new UnityContainer();
container.RegisterType<IMyService, MyService>();
var service = container.Resolve<IMyService>(new ParameterOverrides
{
{"initialValue", 42}
});

问题是您可以删除第二个语句代码仍然可以编译,但现在它不再有效了:

IUnityContainer container = new UnityContainer();
var service = container.Resolve<IMyService>(new ParameterOverrides
{
{"initialValue", 42}
});

请注意,缺乏编译时安全性与具体依赖关系无关,但与涉及 DI 容器的事实有关。

这也不是 Unity 的问题;它适用于所有 DI 容器。

There are cases where a DI Container may make sense ,但在大多数情况下,Pure DI是一种更简单、更安全的替代方法:

IMyService service = new MyService(42);

在这里,如果其他人在您看向别处时更改了 API,您将收到编译器错误。很好:compiler errors give you more immediate feedback than run-time errors .


顺便说一句,当您传入原始依赖项并无形中将其变成 Concrete Dependency 时,你让客户更难理解发生了什么。

我建议改为这样设计:

public class MyService : IMyService
{
AnotherClass _anotherObject;
// ...

public MyService(AnotherClass anotherObject)
{
_anotherObject = anotherObject;
}

// ...
}

使用 Pure DI 组合仍然很容易且类型安全:

IMyService service = new MyService(new AnotherClass(42));

关于c# - IoC、依赖注入(inject)和构造函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32992976/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com