当前位置: 首页 > 编程语言 > C#

依赖注入和AppSettings分享

时间:2023-04-10 15:07:42 C#

依赖注入和AppSettings假设我正在为我的应用程序定义一个浏览器实现类:classInternetExplorerBrowser:IBrowser{privatereadonlystringexecutablePath=@"C:ProgramFiles......即.exe";...使用executablePath的代码}乍一看这似乎是个好主意,因为executablePath数据接近将使用它的代码。当我尝试在另一台使用外语操作系统executablePath的计算机上运行相同的应用程序时,会出现问题:executablePath将具有不同的值。我可以使用AppSettings单例类(或其等效类之一)来解决这个问题,但没有人知道我的类实际上依赖于这个AppSettings类(它违背了DIideias)。它还会使单元测试变得困难。我可以通过在构造函数中传递executablePath来解决这两个问题:classInternetExplorerBrowser:IBrowser{privatereadonlystringexecutablePath;publicInternetExplorerBrowser(stringexecutablePath){this.executablePath=executablePath;但这将在我的CompositionRoot中(将是完成所有需要的类连接的start方法)因为该方法必须知道如何连接并且必须知道所有这些小设置数据:classCompositionRoot{publicvoidRun(){ClassAclassA=newClassA();stringieSetting1="C:asdapopokaposkdaposka.exe";字符串ieSetting2="IE_SETTING_ABC";stringieSetting3="lol.bmp";ClassBclassB=newClassB(ieSetting1);ClassCclassC=newClassC(B,ieSetting2,ieSetting3);...}}这很容易变成一团糟。我可以通过传递表单接口IAppSettings{objectGetData(stringname);的接口来解决这个问题}所有需要某种设置的类。然后我可以将它实现为一个嵌入了所有设置的常规类,或者一个从XML文件读取数据的类。如果我这样做,我应该为整个系统提供一个AppSettings类的公共实例,还是让每个可能需要一个的类关联一个AppSettings类?这当然看起来有点矫枉过正。此外,将所有应用程序设置集中在一个地方可以很容易地查看和查看我在尝试将程序移动到不同平台时需要进行的所有更改。解决这种常见情况的最佳方法是什么?编辑:如何使用IAppSettings及其所有硬编码设置?接口IAppSettings{字符串IE_ExecutablePath{得到;}intIE_Version{得到;}...}这将允许编译时类型安全。如果我看到接口/具体类增长太多,我可以创建IMyClassXAppSettingsforms的其他更小的接口。医疗/重大项目是否负担过重?我还阅读了有关AOP及其在处理横切问题方面的优势(我想这就是其中之一)。它不也提供了解决这个问题的方法吗?也许像这样标记一个变量:classInternetExplorerBrowser:IBrowser{[AppSetting]stringexecutablePath;[AppSetting]intieVersion;...使用executablePath的代码}然后,在编译项目时,我们还具有编译时安全性(让编译器检查我们是否实际执行了封送数据的代码)。当然,这将我们的API与这个特定方面联系在一起。各个类应该尽可能独立于底层结构-IAppSettings组合细节,如IAppSettings、IMyClassXAppSettings和[AppSetting]放入类中,这是最简单的,真正只依赖于原始值,如executablePath。依赖注入的艺术在注意因素中。我已经使用Autofac实现了这个确切的模式,它有一个类似于Ninject的模块,并且应该产生类似的代码(我意识到这个问题没有提到Ninject,但是OP在评论中提到了)。模块通过公开子系统的子系统可配置元素组织应用程序模块:publicclassBrowserModule:Module{privatereadonlystring_executablePath;publicBrowserModule(stringexecutablePath){_executablePath=executablePath;}publicoverridevoidLoad(ContainerBuilderbuilder){builder.Register(c=>newInternetExplorerBrowser(_executablePath)).As().InstancePerDependency();这使得组合根有同样的问题:它必须为executablePath提供一个值。为了避免配置,我们可以编写一个独立的模块来读取配置设置并将它们传递给BrowserModule:publicclassConfiguredBrowserModule:Modulebuilder.RegisterModule(新浏览器模块(executablePath));您可能会考虑使用自定义配置部分而不是AppSettings;更改将本地化到模块:}设置{这个["executablePath"]=值;}}}publicclassConfiguredBrowserModule:Module{publicoverridevoidLoad(ContainerBuilderbuilder){varsection=(BrowserSection)ConfigurationManager.GetSection("myApp.browser");if(section==null){section=newBrowserSection();}builder.RegisterModule(newBrowserModule(section.ExecutablePath));这是一个很好的模式,因为每个子系统都有一个独立的配置,可以在一个地方读取。这里唯一的好处是更明显的意图。但是,对于非字符串值或复杂模式,我们可以让System.Configuration来完成繁重的工作。我会选择最后一个选项——传入一个符合IAppSettings接口的对象。事实上,我最近在工作中执行了重构以整理一些单元测试,并且效果很好。但是,很少有类依赖于此项目中的设置。我会创建一个设置类的实例并将它传递给任何依赖它的东西。我看不出任何潜在的问题。但是,我认为您已经考虑过这一点并且看到如果您有很多依赖于设置的类会有多痛苦。如果这对您来说是个问题,您可以使用诸如ninject之类的依赖项注入框架来解决它(抱歉,如果您已经知道像ninject这样的项目-这听起来可能有点傲慢-如果您不熟悉为什么在github上使用ninject部分是一个学习的好地方)。使用ninject,对于您的主项目,您可以声明您希望任何依赖IAppSettings类使用基于AppSettings的类的单例实例,而不必在任何地方显式地将其传递给构造函数。然后,您可以通过声明要在任何使用MockAppSettings的地方使用IAppSettings实例,或者直接显式传递模拟对象来为单元测试设置不同的系统。我希望我的问题得到正确的答案并且我帮助了你-你已经听起来像你知道你在做什么:)这就是C#学习教程的全部内容:依赖注入和AppSettings有用并且需要了解更多关于C#学习教程,我希望大家以后会多多关注~本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: