我正在使用带有DirectoryModuleCatalog的Prism V2,我需要按特定顺序初始化模块.使用每个IModule实现的属性指定所需的顺序.
这样,每个模块初始化时,都会将其View添加到TabControl区域,并且选项卡的顺序必须是模块作者确定的并由模块作者控制.
顺序并不意味着依赖,而只是一个它们应该被初始化的顺序.换句话说:模块A,B和C可以分别具有1,2和3的优先级.B没有对A的依赖 - 它只需要在 A 之后加载到TabControl区域.这样我们就有了一个确定性和可控的选项卡顺序.此外,B可能在运行时不存在; 因此它们将加载为A,C,因为优先级应确定顺序(1,3).如果我使用ModuleDependency,那么模块"C"将无法加载w/o的所有依赖项.
我可以管理如何对模块进行排序的逻辑,但我无法弄清楚在哪里放置所述逻辑.
Fer*_*own 13
我不喜欢使用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; }
}
Run Code Online (Sandbox Code Playgroud)
然后我装饰了这样的模块:
[Priority(200)]
[Module(ModuleName = "MyModule")]
public class MyModule : IModule
Run Code Online (Sandbox Code Playgroud)
我创建了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;
}
}
Run Code Online (Sandbox Code Playgroud)
最后,我更改了引导程序以使用这个新目录:
/// <summary>Where are the modules located</summary>
/// <returns></returns>
protected override IModuleCatalog GetModuleCatalog()
{
return new PrioritizedDirectoryModuleCatalog() { ModulePath = @".\Modules" };
}
Run Code Online (Sandbox Code Playgroud)
我不确定装配装载的东西是不是最好的做事方式,但它似乎有用......
| 归档时间: |
|
| 查看次数: |
10927 次 |
| 最近记录: |