Prism中如何控制模块初始化的顺序

发布于 2024-08-03 02:29:37 字数 437 浏览 2 评论 0原文

我将 Prism V2 与 DirectoryModuleCatalog 一起使用,并且需要按特定顺序初始化模块。所需的顺序由每个 IModule 实现上的属性指定。

这样,当每个模块初始化时,它们会将其视图添加到 TabControl 区域中,并且选项卡的顺序需要确定并由模块作者控制。

该顺序并不意味着依赖关系,而只是它们初始化的顺序。换句话说:模块 A、B 和 C 的优先级可能分别为 1、2 和 3。 B 不依赖于 A - 它只需要在 A 之后加载到 TabControl 区域中。这样我们就有了确定且可控的选项卡顺序。另外,B 在运行时可能不存在;因此它们将加载为 A, C,因为优先级应确定顺序 (1, 3)。如果我使用 ModuleDependency,那么模块“C”将无法加载其所有依赖项。

我可以管理如何对模块进行排序的逻辑,但我无法弄清楚将所述逻辑放在哪里

I'm using Prism V2 with a DirectoryModuleCatalog and I need the modules to be initialized in a certain order. The desired order is specified with an attribute on each IModule implementation.

This is so that as each module is initialized, they add their View into a TabControl region and the order of the tabs needs to be deterministic and controlled by the module author.

The order does not imply a dependency, but rather just an order that they should be initialized in. In other words: modules A, B, and C may have priorities of 1, 2, and 3 respectively. B does not have a dependency on A - it just needs to get loaded into the TabControl region after A. So that we have a deterministic and controllable order of the tabs. Also, B might not exist at runtime; so they would load as A, C because the priority should determine the order (1, 3). If i used the ModuleDependency, then module "C" will not be able to load w/o all of it's dependencies.

I can manage the logic of how to sort the modules, but i can't figure out where to put said logic.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

热风软妹 2024-08-10 02:29:37

我不喜欢使用 ModuleDependency 的想法,因为这意味着当模块 b 不存在时,模块 a 不会加载,而实际上没有依赖项。相反,我创建了一个优先级属性来装饰模块:

/// <summary>
/// Allows the order of module loading to be controlled.  Where dependencies
/// allow, module loading order will be controlled by relative values of priority
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class PriorityAttribute : Attribute
{
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="priority">the priority to assign</param>
    public PriorityAttribute(int priority)
    {
        this.Priority = priority;
    }

    /// <summary>
    /// Gets or sets the priority of the module.
    /// </summary>
    /// <value>The priority of the module.</value>
    public int Priority { get; private set; }
}

然后我像这样装饰模块:

[Priority(200)]
[Module(ModuleName = "MyModule")]
public class MyModule : IModule

我创建了 DirectoryModuleCatalog 的新后代:

/// <summary>
/// ModuleCatalog that respects PriorityAttribute for sorting modules
/// </summary>
[SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)]
public class PrioritizedDirectoryModuleCatalog : DirectoryModuleCatalog
{
    /// <summary>
    /// local class to load assemblies into different appdomain which is then discarded
    /// </summary>
    private class ModulePriorityLoader : MarshalByRefObject
    {
        /// <summary>
        /// Get the priorities
        /// </summary>
        /// <param name="modules"></param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
        public Dictionary<string, int> GetPriorities(IEnumerable<ModuleInfo> modules)
        {
            //retrieve the priorities of each module, so that we can use them to override the 
            //sorting - but only so far as we don't mess up the dependencies
            var priorities = new Dictionary<string, int>();
            var assemblies = new Dictionary<string, Assembly>();

            foreach (ModuleInfo module in modules)
            {
                if (!assemblies.ContainsKey(module.Ref))
                {
                    //LoadFrom should generally be avoided appently due to unexpected side effects,
                    //but since we are doing all this in a separate AppDomain which is discarded
                    //this needn't worry us
                    assemblies.Add(module.Ref, Assembly.LoadFrom(module.Ref));
                }

                Type type = assemblies[module.Ref].GetExportedTypes()
                    .Where(t => t.AssemblyQualifiedName.Equals(module.ModuleType, StringComparison.Ordinal))
                    .First();

                var priorityAttribute =
                    CustomAttributeData.GetCustomAttributes(type).FirstOrDefault(
                        cad => cad.Constructor.DeclaringType.FullName == typeof(PriorityAttribute).FullName);

                int priority;
                if (priorityAttribute != null)
                {
                    priority = (int)priorityAttribute.ConstructorArguments[0].Value;
                }
                else
                {
                    priority = 0;
                }

                priorities.Add(module.ModuleName, priority);
            }

            return priorities;
        }
    }

    /// <summary>
    /// Get the priorities that have been assigned to each module.  If a module does not have a priority 
    /// assigned (via the Priority attribute) then it is assigned a priority of 0
    /// </summary>
    /// <param name="modules">modules to retrieve priorities for</param>
    /// <returns></returns>
    private Dictionary<string, int> GetModulePriorities(IEnumerable<ModuleInfo> modules)
    {
        AppDomain childDomain = BuildChildDomain(AppDomain.CurrentDomain);
        try
        {
            Type loaderType = typeof(ModulePriorityLoader);
            var loader =
                (ModulePriorityLoader)
                childDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();

            return loader.GetPriorities(modules);
        }
        finally
        {
            AppDomain.Unload(childDomain);
        }
    }

    /// <summary>
    /// Sort modules according to dependencies and Priority
    /// </summary>
    /// <param name="modules">modules to sort</param>
    /// <returns>sorted modules</returns>
    protected override IEnumerable<ModuleInfo> Sort(IEnumerable<ModuleInfo> modules)
    {
        Dictionary<string, int> priorities = GetModulePriorities(modules);
        //call the base sort since it resolves dependencies, then re-sort 
        var result = new List<ModuleInfo>(base.Sort(modules));
        result.Sort((x, y) =>
            {
                string xModuleName = x.ModuleName;
                string yModuleName = y.ModuleName;
                //if one depends on other then non-dependent must come first
                //otherwise base on priority
                if (x.DependsOn.Contains(yModuleName))
                    return 1; //x after y
                else if (y.DependsOn.Contains(xModuleName))
                    return -1; //y after x
                else 
                    return priorities[xModuleName].CompareTo(priorities[yModuleName]);
            });

        return result;
    }
}

最后,我更改了引导程序以使用这个新目录:

    /// <summary>Where are the modules located</summary>
    /// <returns></returns>
    protected override IModuleCatalog GetModuleCatalog()
    {
        return new PrioritizedDirectoryModuleCatalog() { ModulePath = @".\Modules" };
    }

我不确定是否带有程序集加载的内容是最好的做事方式,但它似乎有效......

I didn't like the idea of using ModuleDependency because this would mean that module a would not load when module b was not present, when in fact there was no dependency. Instead I created a priority attribute to decorate the module:

/// <summary>
/// Allows the order of module loading to be controlled.  Where dependencies
/// allow, module loading order will be controlled by relative values of priority
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class PriorityAttribute : Attribute
{
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="priority">the priority to assign</param>
    public PriorityAttribute(int priority)
    {
        this.Priority = priority;
    }

    /// <summary>
    /// Gets or sets the priority of the module.
    /// </summary>
    /// <value>The priority of the module.</value>
    public int Priority { get; private set; }
}

I then decorated the modules like this:

[Priority(200)]
[Module(ModuleName = "MyModule")]
public class MyModule : IModule

I created a new descendent of DirectoryModuleCatalog:

/// <summary>
/// ModuleCatalog that respects PriorityAttribute for sorting modules
/// </summary>
[SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)]
public class PrioritizedDirectoryModuleCatalog : DirectoryModuleCatalog
{
    /// <summary>
    /// local class to load assemblies into different appdomain which is then discarded
    /// </summary>
    private class ModulePriorityLoader : MarshalByRefObject
    {
        /// <summary>
        /// Get the priorities
        /// </summary>
        /// <param name="modules"></param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
        public Dictionary<string, int> GetPriorities(IEnumerable<ModuleInfo> modules)
        {
            //retrieve the priorities of each module, so that we can use them to override the 
            //sorting - but only so far as we don't mess up the dependencies
            var priorities = new Dictionary<string, int>();
            var assemblies = new Dictionary<string, Assembly>();

            foreach (ModuleInfo module in modules)
            {
                if (!assemblies.ContainsKey(module.Ref))
                {
                    //LoadFrom should generally be avoided appently due to unexpected side effects,
                    //but since we are doing all this in a separate AppDomain which is discarded
                    //this needn't worry us
                    assemblies.Add(module.Ref, Assembly.LoadFrom(module.Ref));
                }

                Type type = assemblies[module.Ref].GetExportedTypes()
                    .Where(t => t.AssemblyQualifiedName.Equals(module.ModuleType, StringComparison.Ordinal))
                    .First();

                var priorityAttribute =
                    CustomAttributeData.GetCustomAttributes(type).FirstOrDefault(
                        cad => cad.Constructor.DeclaringType.FullName == typeof(PriorityAttribute).FullName);

                int priority;
                if (priorityAttribute != null)
                {
                    priority = (int)priorityAttribute.ConstructorArguments[0].Value;
                }
                else
                {
                    priority = 0;
                }

                priorities.Add(module.ModuleName, priority);
            }

            return priorities;
        }
    }

    /// <summary>
    /// Get the priorities that have been assigned to each module.  If a module does not have a priority 
    /// assigned (via the Priority attribute) then it is assigned a priority of 0
    /// </summary>
    /// <param name="modules">modules to retrieve priorities for</param>
    /// <returns></returns>
    private Dictionary<string, int> GetModulePriorities(IEnumerable<ModuleInfo> modules)
    {
        AppDomain childDomain = BuildChildDomain(AppDomain.CurrentDomain);
        try
        {
            Type loaderType = typeof(ModulePriorityLoader);
            var loader =
                (ModulePriorityLoader)
                childDomain.CreateInstanceFrom(loaderType.Assembly.Location, loaderType.FullName).Unwrap();

            return loader.GetPriorities(modules);
        }
        finally
        {
            AppDomain.Unload(childDomain);
        }
    }

    /// <summary>
    /// Sort modules according to dependencies and Priority
    /// </summary>
    /// <param name="modules">modules to sort</param>
    /// <returns>sorted modules</returns>
    protected override IEnumerable<ModuleInfo> Sort(IEnumerable<ModuleInfo> modules)
    {
        Dictionary<string, int> priorities = GetModulePriorities(modules);
        //call the base sort since it resolves dependencies, then re-sort 
        var result = new List<ModuleInfo>(base.Sort(modules));
        result.Sort((x, y) =>
            {
                string xModuleName = x.ModuleName;
                string yModuleName = y.ModuleName;
                //if one depends on other then non-dependent must come first
                //otherwise base on priority
                if (x.DependsOn.Contains(yModuleName))
                    return 1; //x after y
                else if (y.DependsOn.Contains(xModuleName))
                    return -1; //y after x
                else 
                    return priorities[xModuleName].CompareTo(priorities[yModuleName]);
            });

        return result;
    }
}

Finally, I changed the bootstrapper to use this new catalog:

    /// <summary>Where are the modules located</summary>
    /// <returns></returns>
    protected override IModuleCatalog GetModuleCatalog()
    {
        return new PrioritizedDirectoryModuleCatalog() { ModulePath = @".\Modules" };
    }

I'm not sure if the stuff with assembly loading is the best way to do things, but it seems to work...

做个少女永远怀春 2024-08-10 02:29:37

您可以在模块类上使用 ModuleDependency 属性来告诉加载器您的模块依赖于其他模块:

[ModuleDependency("SomeModule")]
[ModuleDependency("SomeOtherModule")]
public class MyModule : IModule
{
}

You can use the ModuleDependency attribute on your module class to tell the loader that your module depends on other modules:

[ModuleDependency("SomeModule")]
[ModuleDependency("SomeOtherModule")]
public class MyModule : IModule
{
}
谈情不如逗狗 2024-08-10 02:29:37

您可以将默认的IModuleInitializer替换为自定义类的实例,该实例不是在加载模块后立即对其进行初始化,而是将它们存储在模块列表中。加载所有模块后,您可以按照您想要的顺序初始化它们。

如何实现这一点:

1) 在引导程序中,重写 ConfigureContainer 方法来替换 MyModuleInitializer 类实例的默认 IModuleInitializer,但使用名称维护默认初始化程序(例如,defaultModuleInitializer):


protected override void ConfigureContainer()
{
    base.ConfigureContainer();
    var defaultContainer = Container.Resolve<IModuleInitializer>();
    Container.RegisterInstance<IModuleInitializer>("defaultModuleInitializer", defaultContainer);
    Container.RegisterType<IModuleInitializer, MyModuleInitializer>(new ContainerControlledLifetimeManager());
}

2) 创建执行所需的 storea-all-then-sort-and-initialize 过程的 MyModuleInitializer 类:


public class MyModuleInitializer : IModuleInitializer
{
    bool initialModuleLoadCompleted = false;
    IModuleInitializer defaultInitializer = null;
    List<ModuleInfo> modules = new List<ModuleInfo>();

    public MyModuleInitializer(IUnityContainer container)
    {
        defaultInitializer = container.Resolve<IModuleInitializer>("defaultModuleInitializer");
    }

    public void Initialize(ModuleInfo moduleInfo)
    {
        if(initialModuleLoadCompleted) {
            //Module loaded on demand after application startup - use the default initializer
            defaultInitializer.Initialize(moduleInfo);
            return;
        }

        modules.Add(moduleInfo);

        if(AllModulesLoaded()) {
            SortModules();
            foreach(var module in modules) {
                defaultInitializer.Initialize(module);
            }
            modules = null;
            initialModuleLoadCompleted = true;
        }
    }

    private bool AllModulesLoaded()
    {
        //Here you check whether all the startup modules have been loaded
        //(perhaps by looking at the module catalog) and return true if so
    }

    private void SortModules()
    {
        //Here you sort the "modules" list however you want
    }
}

请注意,加载所有启动模块后,此类将恢复为简单地调用默认初始化程序。如果这不是您所需要的,请适当调整课程。

You can replace the default IModuleInitializer for an instance of a custom class that instead of initializing the modules right after they are loaded, stores them in a modules list. When all modules have been loaded, you initialize them in whatever order you want.

How to achieve this:

1) In the bootstrapper, override the ConfigureContainer method to replace the default IModuleInitializer for a instance of the MyModuleInitializer class, yet maintaining the default initializer with a name (for example, defaultModuleInitializer):


protected override void ConfigureContainer()
{
    base.ConfigureContainer();
    var defaultContainer = Container.Resolve<IModuleInitializer>();
    Container.RegisterInstance<IModuleInitializer>("defaultModuleInitializer", defaultContainer);
    Container.RegisterType<IModuleInitializer, MyModuleInitializer>(new ContainerControlledLifetimeManager());
}

2) Create the MyModuleInitializer class that performs the desired storea-all-then-sort-and-initialize procedure:


public class MyModuleInitializer : IModuleInitializer
{
    bool initialModuleLoadCompleted = false;
    IModuleInitializer defaultInitializer = null;
    List<ModuleInfo> modules = new List<ModuleInfo>();

    public MyModuleInitializer(IUnityContainer container)
    {
        defaultInitializer = container.Resolve<IModuleInitializer>("defaultModuleInitializer");
    }

    public void Initialize(ModuleInfo moduleInfo)
    {
        if(initialModuleLoadCompleted) {
            //Module loaded on demand after application startup - use the default initializer
            defaultInitializer.Initialize(moduleInfo);
            return;
        }

        modules.Add(moduleInfo);

        if(AllModulesLoaded()) {
            SortModules();
            foreach(var module in modules) {
                defaultInitializer.Initialize(module);
            }
            modules = null;
            initialModuleLoadCompleted = true;
        }
    }

    private bool AllModulesLoaded()
    {
        //Here you check whether all the startup modules have been loaded
        //(perhaps by looking at the module catalog) and return true if so
    }

    private void SortModules()
    {
        //Here you sort the "modules" list however you want
    }
}

Note that after all the startup modules have been loaded, this class reverts to simply invoking the default initializer. Adapt the class appropriately if this is not what you need.

Spring初心 2024-08-10 02:29:37

我通过使用 ModuleDependency 属性解决了这个问题,它的作用就像一个魅力

I resolved this by using the ModuleDependency attribute and it worked like a charm

蓝海 2024-08-10 02:29:37

在 Bootstrapper 的 AddModule() 调用中,您可以指定依赖项。因此,您可以说 A 依赖于 B 依赖于 C,这将决定加载顺序。

http://msdn.microsoft.com/en-us/magazine/cc785479。 ASPX

In the AddModule() call in the Bootstrapper, you can specify a dependency. So, you can say A depends on B depends on C, and that will determine load order.

http://msdn.microsoft.com/en-us/magazine/cc785479.aspx

格子衫的從容 2024-08-10 02:29:37

让这个起死回生,因为我似乎找到了一个不同的解决方案,有些人可能会觉得有用。我尝试了一下,它有效,但我还没有摸索出所有的优点和缺点。

我使用 DirectoryModuleCatalog 来获取所有模块的列表,这些模块全部放入一个文件夹中。但我注意到,在大多数情况下,我的所有“视图”模块都依赖于我的“服务”模块,这是一种非常常见的模式。任何服务都不应该依赖于视图。这让我开始思考,如果我们将所有服务模块放入一个文件夹中,将所有视图模块放入另一个文件夹中,并按正确的顺序创建两个不同的目录,会怎样。经过一番挖掘,我发现了这篇文章 其中提到了称为 AggregateModuleCatalog 的东西,它用于将一堆目录连接在一起。我在此处找到了此类的源代码。以下是我使用它的方式:

class Bootstrapper : UnityBootstrapper
{
    protected override System.Windows.DependencyObject CreateShell() {...}
    protected override void InitializeShell() {...}

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new AggregateModuleCatalog();
    }

    protected override void ConfigureModuleCatalog()
    {
        ((AggregateModuleCatalog)ModuleCatalog).AddCatalog(new DirectoryModuleCatalog { ModulePath = "Modules.Services" });
        ((AggregateModuleCatalog)ModuleCatalog).AddCatalog(new DirectoryModuleCatalog { ModulePath = "Modules.Views" });
    }
}

还有 AggregateModuleCatalog:

public class AggregateModuleCatalog : IModuleCatalog
{
    private List<IModuleCatalog> catalogs = new List<IModuleCatalog>();

    /// <summary>
    /// Initializes a new instance of the <see cref="AggregateModuleCatalog"/> class.
    /// </summary>
    public AggregateModuleCatalog()
    {
        this.catalogs.Add(new ModuleCatalog());
    }

    /// <summary>
    /// Gets the collection of catalogs.
    /// </summary>
    /// <value>A read-only collection of catalogs.</value>
    public ReadOnlyCollection<IModuleCatalog> Catalogs
    {
        get
        {
            return this.catalogs.AsReadOnly();
        }
    }

    /// <summary>
    /// Adds the catalog to the list of catalogs
    /// </summary>
    /// <param name="catalog">The catalog to add.</param>
    public void AddCatalog(IModuleCatalog catalog)
    {
        if (catalog == null)
        {
            throw new ArgumentNullException("catalog");
        }

        this.catalogs.Add(catalog);
    }

    /// <summary>
    /// Gets all the <see cref="ModuleInfo"/> classes that are in the <see cref="ModuleCatalog"/>.
    /// </summary>
    /// <value></value>
    public IEnumerable<ModuleInfo> Modules
    {
        get
        {
            return this.Catalogs.SelectMany(x => x.Modules);
        }
    }

    /// <summary>
    /// Return the list of <see cref="ModuleInfo"/>s that <paramref name="moduleInfo"/> depends on.
    /// </summary>
    /// <param name="moduleInfo">The <see cref="ModuleInfo"/> to get the</param>
    /// <returns>
    /// An enumeration of <see cref="ModuleInfo"/> that <paramref name="moduleInfo"/> depends on.
    /// </returns>
    public IEnumerable<ModuleInfo> GetDependentModules(ModuleInfo moduleInfo)
    {
        var catalog = this.catalogs.Single(x => x.Modules.Contains(moduleInfo));
        return catalog.GetDependentModules(moduleInfo);
    }

    /// <summary>
    /// Returns the collection of <see cref="ModuleInfo"/>s that contain both the <see cref="ModuleInfo"/>s in
    /// <paramref name="modules"/>, but also all the modules they depend on.
    /// </summary>
    /// <param name="modules">The modules to get the dependencies for.</param>
    /// <returns>
    /// A collection of <see cref="ModuleInfo"/> that contains both all <see cref="ModuleInfo"/>s in <paramref name="modules"/>
    /// and also all the <see cref="ModuleInfo"/> they depend on.
    /// </returns>
    public IEnumerable<ModuleInfo> CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)
    {
        var modulesGroupedByCatalog = modules.GroupBy<ModuleInfo, IModuleCatalog>(module => this.catalogs.Single(catalog => catalog.Modules.Contains(module)));
        return modulesGroupedByCatalog.SelectMany(x => x.Key.CompleteListWithDependencies(x));
    }

    /// <summary>
    /// Initializes the catalog, which may load and validate the modules.
    /// </summary>
    public void Initialize()
    {
        foreach (var catalog in this.Catalogs)
        {
            catalog.Initialize();
        }
    }

    /// <summary>
    /// Adds a <see cref="ModuleInfo"/> to the <see cref="ModuleCatalog"/>.
    /// </summary>
    /// <param name="moduleInfo">The <see cref="ModuleInfo"/> to add.</param>
    public void AddModule(ModuleInfo moduleInfo)
    {
        this.catalogs[0].AddModule(moduleInfo);
    }
}

我还应该提到该文章指出了以下内容:

为了演示使用 ModuleCatalog 的多种方法,
使用 Unity 的 QuickStart 实现了 AggregateModuleCatalog
源自 IModuleCatalog。该类不适合用于
运输申请。

我不确定为什么会这样。很想听到任何关于原因的解释。

Bringing this back from the dead as I seem to have found a different solution that some might find useful. I tried it out and it works but I have yet to feel out all the pros and cons.

I was using DirectoryModuleCatalog to get a list of all my modules which were all placed into a single folder. But I noticed that for the most part all my "View" modules depended on my "Service" modules, and that was a pretty common pattern. No service should depend on a view. So that got me thinking, what if we just put all the service modules into a folder and all the view modules into another and created two different catalogs in the correct order. Some digging around and I found this article that mentions something called an AggregateModuleCatalog, and it's used to concatenate together a bunch of catalogs. I found the source code for this class here. And here's how I used it:

class Bootstrapper : UnityBootstrapper
{
    protected override System.Windows.DependencyObject CreateShell() {...}
    protected override void InitializeShell() {...}

    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new AggregateModuleCatalog();
    }

    protected override void ConfigureModuleCatalog()
    {
        ((AggregateModuleCatalog)ModuleCatalog).AddCatalog(new DirectoryModuleCatalog { ModulePath = "Modules.Services" });
        ((AggregateModuleCatalog)ModuleCatalog).AddCatalog(new DirectoryModuleCatalog { ModulePath = "Modules.Views" });
    }
}

And the AggregateModuleCatalog:

public class AggregateModuleCatalog : IModuleCatalog
{
    private List<IModuleCatalog> catalogs = new List<IModuleCatalog>();

    /// <summary>
    /// Initializes a new instance of the <see cref="AggregateModuleCatalog"/> class.
    /// </summary>
    public AggregateModuleCatalog()
    {
        this.catalogs.Add(new ModuleCatalog());
    }

    /// <summary>
    /// Gets the collection of catalogs.
    /// </summary>
    /// <value>A read-only collection of catalogs.</value>
    public ReadOnlyCollection<IModuleCatalog> Catalogs
    {
        get
        {
            return this.catalogs.AsReadOnly();
        }
    }

    /// <summary>
    /// Adds the catalog to the list of catalogs
    /// </summary>
    /// <param name="catalog">The catalog to add.</param>
    public void AddCatalog(IModuleCatalog catalog)
    {
        if (catalog == null)
        {
            throw new ArgumentNullException("catalog");
        }

        this.catalogs.Add(catalog);
    }

    /// <summary>
    /// Gets all the <see cref="ModuleInfo"/> classes that are in the <see cref="ModuleCatalog"/>.
    /// </summary>
    /// <value></value>
    public IEnumerable<ModuleInfo> Modules
    {
        get
        {
            return this.Catalogs.SelectMany(x => x.Modules);
        }
    }

    /// <summary>
    /// Return the list of <see cref="ModuleInfo"/>s that <paramref name="moduleInfo"/> depends on.
    /// </summary>
    /// <param name="moduleInfo">The <see cref="ModuleInfo"/> to get the</param>
    /// <returns>
    /// An enumeration of <see cref="ModuleInfo"/> that <paramref name="moduleInfo"/> depends on.
    /// </returns>
    public IEnumerable<ModuleInfo> GetDependentModules(ModuleInfo moduleInfo)
    {
        var catalog = this.catalogs.Single(x => x.Modules.Contains(moduleInfo));
        return catalog.GetDependentModules(moduleInfo);
    }

    /// <summary>
    /// Returns the collection of <see cref="ModuleInfo"/>s that contain both the <see cref="ModuleInfo"/>s in
    /// <paramref name="modules"/>, but also all the modules they depend on.
    /// </summary>
    /// <param name="modules">The modules to get the dependencies for.</param>
    /// <returns>
    /// A collection of <see cref="ModuleInfo"/> that contains both all <see cref="ModuleInfo"/>s in <paramref name="modules"/>
    /// and also all the <see cref="ModuleInfo"/> they depend on.
    /// </returns>
    public IEnumerable<ModuleInfo> CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)
    {
        var modulesGroupedByCatalog = modules.GroupBy<ModuleInfo, IModuleCatalog>(module => this.catalogs.Single(catalog => catalog.Modules.Contains(module)));
        return modulesGroupedByCatalog.SelectMany(x => x.Key.CompleteListWithDependencies(x));
    }

    /// <summary>
    /// Initializes the catalog, which may load and validate the modules.
    /// </summary>
    public void Initialize()
    {
        foreach (var catalog in this.Catalogs)
        {
            catalog.Initialize();
        }
    }

    /// <summary>
    /// Adds a <see cref="ModuleInfo"/> to the <see cref="ModuleCatalog"/>.
    /// </summary>
    /// <param name="moduleInfo">The <see cref="ModuleInfo"/> to add.</param>
    public void AddModule(ModuleInfo moduleInfo)
    {
        this.catalogs[0].AddModule(moduleInfo);
    }
}

I should also mention that the article states the following:

To demonstrate multiple ways of using the ModuleCatalog, the
QuickStart using Unity implements an AggregateModuleCatalog that
derives from IModuleCatalog. This class is not intended to be used in
a shipping application.

Why that is I'm not sure. Would love to hear any explanations as to why that might be.

九八野马 2024-08-10 02:29:37

有一个类似的问题,Fergus Bowns 的答案与 Haukinger 建议的 SmartDirectoryCatalog 相结合: Multiple DirectoryModuleCatalog in a Prism application
。我将其用于“可选依赖项”。希望这会对某人有所帮助。

PS:使用实际的 Prism Unity 7.2,您需要将 ModuleInfo 替换为 IModuleInfo

Had a similar problem an combined Fergus Bowns answer with the SmartDirectoryCatalog suggested by Haukinger: Multiple DirectoryModuleCatalog in a Prism application
. I use this for "optional dependencies". Hope this will help someone.

PS: with the actual Prism Unity 7.2 you need to replace ModuleInfo with IModuleInfo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文