2009-01-06 124 views
2

我们正在开发一款新的手持软件。我不能讨论应用程序的性质,所以我会用一个例子来代替。模块化C#Compact Framework 2.0应用程序

我们正在设计管理学校的手持软件。我们希望模块化系统的各个方面,以便不同的学校可以使用不同的功能。

我们的系统将从主菜单和登录屏幕开始。我希望这是系统的基础,并且将模块添加到哪里。即我会有一个名为SchoolPda的项目。

然后我想拥有不同的模块。即,我想要一个注册模块来处理学生注册。我想要一个教室模块来管理教室的清洁等。

我可能会看到这个工作的方式是包括/不包括不同的dll和基本系统的主菜单暴露按钮来访问这些模块,如果dll存在。这就是我们之后的事情。

有没有人有这样的经验吗?最好的做法是什么?我们不需要担心数据库,因为数据库将始终是完整的数据库,但如果关联的模块不存在,方面将不会被填充。

回答

3

我一直在做它两个方面的项目:

  • 在一个项目中,如果客户不许可的,我们没有部署某些DLL文件。这就是你的建议。它运行良好。当然,如果没有额外的安装,就没有办法启用这些模块,但它对于那个应用程序来说非常合理。

  • 在另一个项目中,我们部署了一切,仅向最终用户展示了客户获得许可的菜单,按钮等。我们这样做是因为用户可以通过为其添加许可证来轻松地添加额外的模块。当许可证被添加时,这些东西神奇地出现在下次登录时。

所以根据我的经验,我会说看看你的授权模式是你决定的一大块。想想你是否想要即时添加这些额外的模块。

0

我不知道它是否能在CLR上工作,但看看MEF,创建一种发现和加载你的DLL /模块的方法。你也可以让你的模块有一个GetMenuItem方法(或者类似的方法)来获取所需的信息,这样你的主菜单就可以添加一个按钮。

很显然,如果有意义的话,可以为主菜单使用不同的设计,但是您希望它可以真实地模块化和可扩展,以便您可以编写核心,并在将来继续编写新组件,而不必改变你的核心。

对不起,如果这不会产生最大量的感觉。只是希望给你一个方向的想法。

3

我目前还在开发一个在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; 
    } 
+0

我们做了类似的事情,但Assembly.LoadFrom是一个昂贵的调用。所以我们切换到了一个xml描述符,在这里我们有所有使用AssemblyName和ClassName定义的插件,这样您就可以直接调用Activator.CreateInstance。 – 2009-01-06 10:46:20

0

原则作品只是让每个模块实现一个共同的接口。添加GetButtons()或GetActions()等方法。

然后,您可以在配置文件中放置有关AssemblyName和ClassName的信息。 现在,它很容易加载指定的程序集并使用Activator.CreateInstance创建类的实例,将其转换为接口并调用GetButtons()等方法。