模块化 C# Compact Framework 2.0 应用程序
-
03-07-2019 - |
题
我们目前正在开发一款新的手持式软件。我无法讨论应用程序的性质,因此我将使用一个示例来代替。
我们正在设计用于管理学校的手持软件。我们希望将系统的各个方面模块化,以便不同的学校可以使用不同的功能。
我们的系统将以主菜单和登录屏幕启动。我希望这是系统的基础,也是添加模块的地方。IE。我将有一个名为 SchoolPda 的项目。
然后我想要不同的模块。即,我想要一个处理学生注册的注册模块。我想要一个用于管理教室清洁等的教室模块。
我可能看到此工作的方式是包含/不包含不同的 dll,并让基本系统的主菜单公开按钮以访问这些模块(如果 dll 存在)。这正是我们所追求的。
有没有人有做这样的事情的经验?最好的方法是什么?我们不需要担心数据库,因为数据库将始终是完整的数据库,但如果关联的模块不存在,方面将不会被填充。
解决方案
我参与过的项目有两种方式:
在一个项目中,如果客户未获得许可,我们就不会部署某些 DLL。这就是你的建议。效果很好。当然,如果不额外安装就无法启用这些模块,但这对于该应用程序来说非常有意义。
在另一个项目中,我们部署了所有内容,只向最终用户公开菜单、按钮等。客户已获得许可。我们这样做是因为用户可以通过添加许可证来轻松添加额外的模块。添加许可证后,这些内容会在下次登录时神奇地出现。
因此,根据我的经验,我想说将您的许可模式视为您决策的重要组成部分。考虑一下您是否想要即时添加这些额外的模块。
其他提示
我目前还在开发一个在Compact和Full框架上运行的应用程序,它是模块化的。
我实现它的方式是它扫描一个位置以获取dll并对每种类型进行消除,并查看它们是否具有“ScreenInfoAttribute”。或“WidgetInfoAttribute”或已定义,其中包含有关该类的有用信息。
这是一个片段,它包含3.5代码,但那是因为我们最近从2.0开始转换,但原理适用于2.0
public void Analyze(FileInfo file) {
Assembly asm = Assembly.LoadFrom(file.FullName);
List<Data.AnyPlugin> types = GetPluginTypes(asm.GetTypes());
if (types.Count > 0) {
types.ForEach(x => x.AssemblyPath = file.FullName);
if (_plugins.ContainsKey(file.FullName)) {
_plugins[file.FullName].Plugins.AddRange(types);
} else {
AssemblyPlugin asp = new AssemblyPlugin();
asp.Ass = asm;
asp.Plugins = types;
_plugins.Add(file.FullName, asp);
}
}
}
private List<Data.AnyPlugin> GetPluginTypes(Type[] types) {
List<Data.AnyPlugin> returnTypes = new List<AnyPlugin>();
foreach (Type t in types) {
Data.AnyPlugin st = GetPluginType(t);
if (st != null) returnTypes.Add(st);
}
return returnTypes;
}
private Data.AnyPlugin GetPluginType(Type type) {
if (type.IsSubclassOf(typeof(Screens.bScreen<T>))) {
Screens.ScreenInfoAttribute s = GetScreenAttrib(type);
if (s != null) {
return new Data.ScreenPlugin("", type, s);
}
} else if (type.IsSubclassOf(typeof(Widgets.bWidget<T>))) {
Widgets.WidgetInfoAttribute w = GetWidgetAttrib(type);
if (w != null) return new Data.WidgetPlugin("", type, w);
}
return null;
}
private Screens.ScreenInfoAttribute GetScreenAttrib(Type t) {
Attribute a = Attribute.GetCustomAttribute(t, typeof(Screens.ScreenInfoAttribute));
return (Screens.ScreenInfoAttribute)a;
}
我不知道它是否适用于CLR,但请查看 MEF ,用于创建发现和加载dll /模块的方法。你也可以让你的模块有一个GetMenuItem方法(或类似的东西)来获取所需的信息,这样你的主菜单就可以添加一个按钮。
显然,如果有意义的话,请在主菜单中使用不同的设计,但是你会希望它真正具有模块化和可扩展性,这样你就可以编写你的核心,并在将来继续编写新的组件,无需改变你的核心。
如果这不是最大的意义,我很抱歉。只是希望在一个方向给你一个想法。
让每个模块实现一个通用接口。添加GetButtons()或GetActions()等方法。
然后,您可以在配置文件中放置有关AssemblyName和ClassName的信息。 现在可以轻松加载指定的Assembly并使用Activator.CreateInstance创建类的实例,将其强制转换为接口并调用GetButtons()等方法。