介绍
这是本人毕业设计的项目,一直想将其整理成文,可一不小心4年就过去了(这个时间又可以读个大学了)。现在给自己定一个目标,一个月时间里将项目的所有关键点都整理出来。不然真怕一眨眼又一个4年过去了,而代码依然躺在硬盘里。
项目取名MathAssist,使用vs2008。分成四个子项目:
- MathAssistLibrary 提供一个接口,以便实现用dll拓展的插件机制
- SuperCalculator 实现任意大数计算的插件
- 命令证明 实现简单逻辑命题证明的插件
- MathAssist 主程序,会扫描并加载其路径下所有符合条件的dll
其主程序可以从插件中扫描可用的命令,也可以显示插件中可用的窗体。如下是主程序界面,其加载了两个插件:“superCalculator”和“命令证明”。它们分别提供命令cal prove。
点击菜单项"插件"的子菜单后可以分别打开两个插件中实现的窗口。如下图
分别实现了大数计算和逻辑命题的证明。
在这篇前言中就先只介绍插件机制的实现吧,大数计算和逻辑命题的证明就留给后面的系列。
插件机制的实现
MathAssistLibrary接口的定义
在MathAssistLibrary项目中只定义了两个接口: ICommand, IForm,分别用于提供命令行功能和窗口功能。
1 /// <summary>命令接口</summary> 2 public interface ICommand 3 { 4 /// <summary>命令名称</summary> 5 string Name { get; } 6 7 /// <summary>执行命令</summary> 8 /// <param name="cmd">命令参数</param> 9 /// <returns>返回的结果</returns>10 string Excute( string cmd );11 12 /// <summary>对命令的使用作相应的说明</summary>13 string Describe { get; }14 }15 /// <summary>获得插件的窗体</summary>16 public interface IForm17 {18 /// <summary>窗体名</summary>19 string Text { get; }20 21 /// <summary>窗体对象</summary>22 Form GetForm { get; }23 }
ICommand接口
- Name 用于表示命令的名称
- Excute 用于执行命令
- Describe 用于对这个命令提供一个简要的帮助文档说明
IForm接口
- Text 用于表示窗体的名称
- GetForm 用于获取Form对象。在主程序中获取Form对象后,再调用Show()即可显示之。
插件实现
在插件项目中只要实现ICommand和IForm两个接口即可,以SuperCalculator为例:
public partial class frmSuperCalculator : Form, IForm{ string IForm.Text { get { return "计算器"; } } frmSuperCalculator frm; Form IForm.GetForm { get { if (frm == null || frm.IsDisposed) { frm = new frmSuperCalculator(); } return frm; } } ... }
public class Calculator : MathAssistLibrary.ICommand{ string MathAssistLibrary.ICommand.Describe { get { return "cal命令可以进行相关的数学运算。比如cal 1+max(2,3)*2"; } } string MathAssistLibrary.ICommand.Name { get { return "cal"; } } string MathAssistLibrary.ICommand.Excute(string cmd) { try { Expression exp = new Expression(); exp.Format = cmd; return exp.Calculator().ToString(); } catch (ExpressionException e) { return string.Format("表达式出错。出错类型:{0},出错位置{1}", e.Message, e.Index); } }}
主程序对插件的扫描
FindDllFile()函数找到与程序同路径下的所有dll文件,代码如下:
1 List<string> FindDllFile(string foldername) { 2 DirectoryInfo dir = new DirectoryInfo(foldername); 3 FileInfo[] files = dir.GetFiles(); 4 List<string> result = new List<string>(); 5 6 foreach (FileInfo fi in files) { 7 if (fi.Name.ToUpper().EndsWith(".DLL")) 8 result.Add(fi.FullName); 9 }10 return result;11 }
LoadOne()从一个文件中找一个特定的类型,并返回其对象,代码如下:
private List<object> LoadOne(string filename, Type type) { List<object> result = new List<object>(); try { Assembly ass = Assembly.LoadFrom(filename); Module[] mods = ass.GetModules(); foreach (Module mod in mods) { Type[] typs = mod.GetTypes(); foreach (Type typ in typs) { if (type.IsAssignableFrom(typ)) { result.Add(ass.CreateInstance(typ.FullName)); } } } } catch (BadImageFormatException) { } return result; } // end func
先用Assembly.LoadFrom()加载程序集,然后获取所有模块,最后在所有模块中用type.IsAssignableFrom()找与传入参数type相匹配的类型,如果匹配那么就创建一个对象并返回。
在主程序中分别用如下两行代码调用LoadOne()
List<object> cmd = LoadOne(filename, typeof(ICommand));List<object> frm = LoadOne(filename, typeof(IForm));
这样用cmd.Excute()就可以执行插件中实现的代码,用frm.Show()就可以显示插件中所实现的窗体。
现提供MathAssist.exe的下载路径。在后面的文章中会给出整个程序的源码,敬请期待~~
参数文献: http://www.cnblogs.com/conexpress/archive/2009/03/04/MyCalculator_01.html
- 3楼诺贝尔
- mark
- 2楼飞翔蚂蚁
- 赞一个!,大数计算不知道和微软提供的BigInteger有什么区别?
- Re: Xiangism
- @飞翔蚂蚁,我的支持浮点运算
- 1楼blackbob
- 请教一下:大数的指数、对数、三角这些超越函数是怎么计算的?
- Re: Xiangism
- @blackbob,泰勒公式~~ 我也是看了代码才记起来