C# 使用字符串的依赖注入(ninject),反模式?
我有一些代码使用ninject注入依赖项,这些依赖项是实际的字符串。例如,这是注入字符串而不是创建新对象的反模式 也就是说,我想注入用户名和密码,创建一个名为credentials的小类,使用Usernamd和Password两个属性,然后注入这个类,会更好吗 将字符串注入构造函数可以通过C# 使用字符串的依赖注入(ninject),反模式?,c#,dependency-injection,ninject,C#,Dependency Injection,Ninject,我有一些代码使用ninject注入依赖项,这些依赖项是实际的字符串。例如,这是注入字符串而不是创建新对象的反模式 也就是说,我想注入用户名和密码,创建一个名为credentials的小类,使用Usernamd和Password两个属性,然后注入这个类,会更好吗 将字符串注入构造函数可以通过 kernel.Bind<IUser>().To<User>() .WithConstructorArgument(@"username", configuration.Us
kernel.Bind<IUser>().To<User>()
.WithConstructorArgument(@"username", configuration.Username)
.WithConstructorArgument(@"password", configuration.Password);
kernel.Bind()到()
.WithConstructorArgument(@“username”,configuration.username)
.WithConstructorArgument(@“password”,configuration.password);
这代码有气味吗
对我正在做的事情有什么想法或改进吗?考虑一个用于保存所有注入接口的程序集。在我当前的工作解决方案(prism,使用MEF)中,我有一个类,它为您指定的用途声明常量字符串 为什么要在文字上使用常量?因为它是一种象征;它是可重构、可发现的,字符串的实际内容并不重要。我总是在字符串上使用GUID作为后缀,以便“保证”唯一性。常量也可用于属性装饰
/// <summary>
/// Exposes top level application region names for use when registering views.
/// </summary>
public static class Regions
{
public const string WORKSPACE_REGION = "WorkspaceRegion {4CCDA460-D1A8-4BCE-863A-593021079F02}"; //names include a GUID to prevent clashes.
public const string TOOL_DIAGRAM_REGION = "ToolDiagramRegigon {AD3CED71-C49D-4BD8-86FF-57E5F35116D3}";
public const string STATUS_REGION = "StatusRegion {4CEF7A12-1E92-4EED-BD46-F70F07E27662}";
public const string TOOLS_REGION = "ToolsRegion {3C6F99B2-6414-4E06-ACC5-7445944FFA29}";
public const string HARDWARE_INTERFACE_REGION = "HardwareInterfaceRegion {4F16ECD1-D3F5-4BE2-BB00-DD148BAE8A83}";
}
//
///公开顶级应用程序区域名称,以便在注册视图时使用。
///
公共静态类区域
{
public const string WORKSPACE_REGION=“WorkspaceRegion{4CCDA460-D1A8-4BCE-863A-593021079F02}”;//名称包括GUID以防止冲突。
public const string TOOL_DIAGRAM_REGION=“tooldiagramregon{AD3CED71-C49D-4BD8-86FF-57E5F35116D3}”;
public const string STATUS_REGION=“StatusRegion{4CEF7A12-1E92-4EED-BD46-F70F07E27662}”;
public const string TOOLS_REGION=“ToolsRegion{3C6F99B2-6414-4E06-ACC5-7445944FFA29}”;
public const string HARDWARE_INTERFACE_REGION=“硬件接口区域{4F16ECD1-D3F5-4BE2-BB00-DD148BAE8A83}”;
}
注意TOOL\u DIAGRAM\u REGION
中的拼写错误。我搞砸了也没关系,因为任何开发人员都不需要再次键入它。我注意到这个错误是因为我在这里粘贴字符串时扫描了字符串
这代码有气味吗
对。创建一个ConfigurationRepository
或创建一个factory/builder(两种不同的设计模式),创建不同的服务,然后在容器中注册该factory/builder
我对这个代码也有问题:
kernel.Bind<IUser>().To<User>()
.WithConstructorArgument(@"username", configuration.Username)
.WithConstructorArgument(@"password", configuration.Password);
kernel.Bind()到()
.WithConstructorArgument(@“username”,configuration.username)
.WithConstructorArgument(@“password”,configuration.password);
IoC容器主要不用于创建域实体,而是用于创建服务/存储库/控制器等,即创建控制应用程序中流的对象。我更喜欢在此处使用
ToMethod()
:
kernel.Bind<IUser>()
.ToMethod(ctx => new User(configuration.Username, configuration.Password));
我竭尽全力避免注入原始类型
查看您发布的代码,我的第一反应是创建一个“IConfigurationService”,并根据需要注入该服务。该服务将包含用户名和密码的属性 这里似乎有两个问题:
最后一点,使用IoC容器管理实体被认为是一种代码味道。实体通常负责在执行域操作时维护域不变量。(不确定示例代码段的上下文/意图是什么,因此无法提供替代方案。)这是一个更一般的答案,但与其直接注入字符串,不如创建接口、提供程序并注入提供程序本身。因此,在将来,如果您需要更改读取和创建字符串的方式,这将更容易。(假设您今天正在从app.config读取它,但随后决定将其存储在DB中,或从注册表读取,或从web请求传递。) 示例应用程序:
public interface IMachineIdProvider
{
//Assume we are returning a machine Id.
String ResolveMachineId();
}
和执行。假设我们正在从webconfig读取它
public class MachineIdProvider : IMachineIdProvider
{
private string _machineId;
public string ResolveMachineId()
{
if (String.IsNullOrEmpty(_machineId))
{
this._machineId= ConfigurationManager.AppSettings["MachineId"];
}
return this._machineId;
}
}
并以这种方式注入:
kernel.Bind<IMachineIdProvider>().To<MachineIdProvider>().InSingletonScope();
所以,无论你在哪里需要使用它,你都可以打电话
var id = _machineIdProvider.ResolveMachineId()
这样,如果您更改获取字符串的方式,您只需更改方法本身或创建另一个要注入的方法。毫无理由地使用逐字字符串文字是不美观的,原因之一:)谢谢Jon,完全正确!因此,理想情况下,最好创建一个具有2个属性的小型类,创建一个接口并将实现注入到
public class MyWonderfulController : BaseController
{
private IMachineIdProvider _machineIdProvider;
public MyWonderfulController(IMachineIdProvider machineIdProvider)
{
this._machineIdProvider = machineIdProvider;
}
}
var id = _machineIdProvider.ResolveMachineId()