【问题标题】:What are the best practicies concerning bootstraping and ioc container?关于引导和 ioc 容器的最佳实践是什么?
【发布时间】:2014-06-24 16:20:00
【问题描述】:

这是我的故事:

我正在开发一个不太大的 WPF/C# 应用程序,在 Unity 框架的帮助下实现(第一次)控制反转。大部分都完成了。我的问题来自我的“引导程序”类,我在 Unity 容器中注册了我的类型。由于涉及的课程数量众多,我的引导程序变得比我想要的要长得多,尽管有 cmets/regions,维护它对我以外的任何人来说都是一种痛苦。所以我想知道是否有更好的方法来处理注册。我在想,也许:

1. “你在抱怨什么?每个人都这样做”嗯,我怀疑它

2。我误解了 ioc 的兴趣,我的太多课程需要注册。 那么,ioc 的兴趣是什么?

3.我只是创建了一个馄饨应用程序,其中包含太多不同的类,我应该合并一些我想我已尽力找到平衡

4.我不应该有一个宏引导程序,但主要的应该调用专门的引导程序,例如库中的一个好吧,这开始听起来不错。毕竟,图书馆本身应该比其他图书馆更了解它们所包含的内容。但是我绝对不知道如何处理它而不让我的容器在每个库中行走,这些库依赖于 Unity...

那么,这一点是好的,还是我只是错过了关于处理注册的好方法的帖子,并且易于维护,任何人都使用?

PS:我没有在标签中提到技术,因为这个问题似乎对每个使用 ioc 容器的应用程序都很常见

编辑:为引导程序添加代码(错误命名的引导加载程序)

这是一个旧版本,现在已经变长了,大约 +15-20%

class Bootloader
{
    public void Run()
    {
        #region SPLASH SCREEN

        Sequenceur.IHM.Views.SplashScreen screen = new Sequenceur.IHM.Views.SplashScreen();
        SplashScreenViewModel screenVM = new SplashScreenViewModel();

        screen.Show();

        #endregion

        #region CONTAINER INITIALIZATION

        UnityContainer container = new UnityContainer();

        container.RegisterType<IMainWorker, Overseer>();

        #endregion

        #region DAL REGISTERATION

        container.RegisterType<IManageData<Product>, LazyProductFilesManager>();
        container.RegisterType<IManageData<Program>, LazyProgramFilesManager>();
        container.RegisterType<IManageData<SequenceResult>, LazyResultFilesManager>();
        #endregion

        #region BOL REGISTERATION

        //Sequence preparation
        container.RegisterType<IProvideProducts, EagerCancellableProductProvider>();
        container.RegisterType<IProvidePrograms, EagerCancellableProgramProvider>();
        container.RegisterType<IPrepareSequence, SequenceInitializer>();

        //Sequence processing
        container.RegisterType<IManagePlugins, MefPluginManager>(new ContainerControlledLifetimeManager());

        //Result Persistence
        container.RegisterType<IPersistSequenceResult, SequenceResultPersister>();
        container.RegisterType<IManageReport, Reporter>(new ContainerControlledLifetimeManager());

        #endregion

        #region UPDATE REGISTERATION

        container.RegisterType<IManageConnection, SqlConnectionManager>();
        container.RegisterType<IUpdateProducts, ProductsUpdater>();
        container.RegisterType<IUpdatePrograms, ProgramsUpdater>();
        container.RegisterType<IUploadResults, ResultsUploader>();
        container.RegisterType<IUpdate, DevelopmentUpdater>(new ContainerControlledLifetimeManager());

        #endregion

        #region HELPERS REGISTERATION

        //Hashing
        container.RegisterType<IHashString, Sha256StringHasher>();

        //Configuration
        container.RegisterType<IPersistConfiguration, ConfigurationPropertiesPersister>();
        container.RegisterType<IConfiguration, EditableConfiguration>();

        //Logging
        container.RegisterType<IManageLoggers, NLoggerManager>();

        //Messengers
        container.RegisterType<IMessagePublisher<Exception>, SimpleMessenger<Exception>>(new ContainerControlledLifetimeManager());
        container.RegisterType<IMessagePublisher<AbortRequest>, SimpleMessenger<AbortRequest>>(new ContainerControlledLifetimeManager());
        container.RegisterType<IMessagePublisher<ConfigData>, SimpleMessenger<ConfigData>>(new ContainerControlledLifetimeManager());
        container.RegisterType<IMessagePublisher<SequenceAction>, SimpleMessenger<SequenceAction>>(new ContainerControlledLifetimeManager());
        container.RegisterType<IMessagePublisher<UpdaterStatus>, SimpleMessenger<UpdaterStatus>>(new ContainerControlledLifetimeManager());
        container.RegisterType<IMessageListener<AbortRequest>>();

        #endregion

        #region IHM REGISTERATION

        container.RegisterType<ILoadMenuViews, SimpleMenuViewLoader>();
        container.RegisterType<IManageScene, SceneManager>();
        container.RegisterType<IProvideOD, WinFormOFDialog>();

        #endregion

        #region CONVERTERS REGISTERATION

        container.RegisterType<IConvertModels<Parameter, dbParameterResult>, ParameterModelsConverter>();
        container.RegisterType<IConvertModels<SequenceActionResult, dbActionResult>, ActionModelsConverter>();
        container.RegisterType<IConvertModels<Tag, dbTag>, TagModelsConverter>();
        container.RegisterType<IConvertModels<Country, dbCountry>, CountryModelsConverter>();
        container.RegisterType<IConvertModels<Segment, dbSegment>, SegmentModelsConverter>();
        container.RegisterType<IConvertModels<Caracteristic, dbCaracteristic>, CaracteristicModelsConverter>();
        container.RegisterType<IConvertModels<Value, dbValue>, ValueModelsConverter>();
        container.RegisterType<IConvertModels<Range, dbRange>, RangeModelsConverter>();
        container.RegisterType<IConvertModels<Subrange, dbSubrange>, SubrangeModelsConverter>();
        container.RegisterType<IConvertModels<Product, dbProduct>, ProductModelsConverter>();
        container.RegisterType<IConvertModels<Program, dbProgram>, ProgramModelsConverter>();
        container.RegisterType<IConvertModels<Tag, dbTag>, TagModelsConverter>();

        #endregion


        #region START

        ShellView mainView = new ShellView();

        mainView.DataContext = container.Resolve<ShellViewModel>();

        screen.Close();

        mainView.Show();

        #endregion
    }
}

【问题讨论】:

  • 你能在你的例子中添加一些代码吗
  • 我们能看到这个引导程序类吗?
  • 好吧,我看不出它有什么帮助,它只不过是一连串的:'container.RegisterType()';和最终解决
  • 您应该使用约定注册这些组件。这是一篇展示 Unity 示例的博客文章:blogs.msdn.com/b/agile/archive/2013/03/12/…

标签: dependency-injection inversion-of-control ioc-container bootstrapping


【解决方案1】:

著名的Mark Seemann 写了一篇博文解释when to use a DI container。他基本上说的是,仅使用“显式寄存器”时,DI 容器的有用性是有限的,容器中每个注册类型都有一行代码(这就是你正在做的事情)。当您使用约定优于配置时,真正的好处就开始了。通过约定优于配置,您将能够在一行代码中注册大量类型,并且您可以防止您的组合根成为维护的噩梦。

虽然我并不完全在同一页面上并且看到“显式寄存器”模型的一些用途,但他是对的,您可以从使用约定优于配置中获得最大的好处。在您的应用程序中,已经有一些明显的地方可以让您从约定优于配置中受益,那就是在注册您的通用抽象时,例如 IManageData&lt;T&gt;、IConvertModels 和 IMessagePublisher&lt;TMessage&gt;

所以你可以做的是创建以下方便的扩展方法:

public static void RegisterManyForOpenGeneric(this UnityContainer container,
    Type openGenericServiceType, params Assembly[] assemblies)
{
    container.RegisterTypes(
        from type in AllClasses.FromAssemblies(assemblies)
        where type.GetInterfaces().Any(i => i.IsGenericType && 
            i.GetGenericTypeDefinition() == openGenericServiceType)
        select type,
        WithMappings.FromMatchingInterface,
        WithName.Default);
}

使用此扩展方法,您可以将通用抽象的注册减少到以下内容:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();

container.RegisterManyForOpenGeneric(typeof(IManageData<>), assemblies);
container.RegisterManyForOpenGeneric(typeof(IConvertModels<,>), assemblies);
container.RegisterManyForOpenGeneric(typeof(IMessagePublisher<>), assemblies);

【讨论】:

  • 这个想法看起来很不错,即使我倾向于谨慎使用 conv 而不是 conf,我也一定会尝试一下。我不会将此方法扩展到“通用助手”之外的其他东西,因为我也认为显式寄存器有它的价值:我可能在我的库中对同一个接口有不同的实现,并且同情项目中的开发人员跳跃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-04
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多