【讨论】从吉日的一段话说起+寻找WinForm架构的最佳实践

这两天园子里最火的莫过于吉日的白话反射,导致包子的批判,然后引来了老赵的两篇文章,然后又有若干人等一堆反射技术文章出世。可谓百花齐放,百家争鸣啊。喜欢这种氛围,呵呵。

今天我不谈反射,但和反射有关

不谈吉日,但话题是从这里开始

吉日的《白话反射》里说到:

"我们在开发大型软件项目时经常会遇到,系统很庞大了有几百M的代码了,主程序启动时,总不能把这些都引用了吧?全部加载在内存里?那程序的启动速度,不知道会不会慢如老牛推车了?这时候也会用一些反射技术等,用到哪个窗体,就动态加载哪个那个窗体,总感觉比较清爽一些。"

表面一看,确实。主模块引用这么多模块,启动的时候那不是很慢,那必须用反射来“制造”一个延迟加载的机制。

实际上,CLR的加载过程是什么样子的呢?(不说的那么详细)

很多书里都介绍了,JIT的编译单元是方法。当执行一个方法之前,会先JIT(即时编译)这个方法,然后发现,这个方法里引用了在别的程序集里定义的类型,那么CLR Loader就会加载这个程序集(更详细的过程可以参见《.Net本质论》或我之前的两篇文章CLR Loader和Assembly Loader)。那这么看来,吉日说的就是错误的,几百M的代码不错,难道这几百M的代码在启动的时候就会全部执行么?如果不执行也就不会JIT,不会JIT也就不会加载这些模块。但是有一个例外:你这几百M代码,全部放在一个模块里(我觉得吉日肯定不会那么干)。

根据上面的讨论,所以吉日说的这种场景不需要用反射,不会影响主程序的启动速度,只需要合理的划分子功能模块就可以了,不要弄得铁板一块。

真的是这样的么?如果光说教我会很快的陷入太虚之中,所以我准备了一个小实验:

image

这个一个典型的WinForm应用的解决方案。Main是主启动项目,而FunctionModule1-FunctionModule4是具体的子功能模块(实际的项目中,肯定不止四个)。

我们看到这里Main项目中引用了四个子功能模块。然后下面是主界面:

image

Function主菜单下有四个子菜单,每个子菜单调用一个子功能模块,菜单的事件代码如下:

   1: private void function1ToolStripMenuItem_Click(object sender, EventArgs e)
   2: {
   3:     Function1 function = new Function1();
   4:     MessageBox.Show(function.ToString());
   5: }
   6: private void function2ToolStripMenuItem_Click(object sender, EventArgs e)
   7: {
   8:     Function2 function = new Function2();
   9:     MessageBox.Show(function.ToString());
  10: }
  11: private void function3ToolStripMenuItem_Click(object sender, EventArgs e)
  12: {
  13:     Function3 function = new Function3();
  14:     MessageBox.Show(function.ToString());
  15: }
  16: private void function4ToolStripMenuItem_Click(object sender, EventArgs e)
  17: {
  18:     Function4 function = new Function4();
  19:     MessageBox.Show(function.ToString());
  20: }

现在问:这里的Main项目启动时,会主动加载这四个子功能模块么?

我们使用Visual Studio调试时输出窗口的功能看看:

image

窗口中,前部分输出的是加载的框架的模块,最后一个是加载Main程序集。但是FunctionModule1-FunctionModule4呢?我仔仔细细寻找了好几遍没发现。那么说明,Main项目启动时,不会主动加载子功能模块的,所以吉日的说法是错误的,除非他把所有子功能模块全部写在主功能模块中。那什么时候加载这些子功能模块?来,我们尝试点一下菜单:

image

子菜单的功能弹出来了,从输出窗口里也发现这个时候加载了FunctionModule1.dll。

以下是对WinForm应用架构设计的讨论

-----------------------------------------------------------------------------------------------------------

下面,我们来讨论一下WinForm应用的架构问题。

我不知道园子里有多少人在做.Net WinForm应用,只是看到园子里大部分人都是在搞Web或WPF。苦恼的我还在搞WinForm,不过也其乐无穷。

上面的实例实际上也给出了大部分WinFrom项目的一个雏形,很多的菜单,每个菜单对应一个功能,打开一个功能的时候要么是Mdi的模式,弹出一个窗口,要么就是一个TabPage。大的工程肯定是一个人完成不了的,需要多个人来做这个事情。但是又需要统一规划。

所以必定是这样的:由架构师来规划好底层支撑的框架,比如这里的Shell,还有一些引擎级别的服务(比如LanguageService“多语言”,PropertyService“持久化软件里某些设置”等)。这个框架必须稳定,项目组其他人员,每个人负责一个或多个功能,每个人只需要关注自己的业务就可以了,把功能做好,然后调用框架里提供的一些服务,把自己给挂接到主框架中。

那么如果按照上面示例的这种设计,我们的程序主框架就必须引用所有的子功能模块,项目开始的时候,可能只有一两个模块,随着项目的前进,引用也在不断的增加,而主界面上的菜单也在不断的增加,这可以说主界面是稳定的么?

那我们必须寻找一种机制。子功能对自己负责,子功能负责自己将自己注册到系统中去。这个时候我们可能采用这样的方式:

一个Modules文件夹,在这个文件夹下又放着很多子文件夹,每个子文件夹里放着一个功能,当系统启动的时候,由框架搜寻Modules子文件夹,在里面查找一个后缀名为addin(或者其他方式)的xml文件,文件里面的内容可能如下:

<MenuItem Site=”File” Text=”Edit” Icon=”Edit.png” CommandType=”MultiLibrariesApp.EditCommand” />

主模块读取这个之后就会生成一个菜单项,当点击这个菜单项的时候,根据CommandType,利用反射实例化一个EditCommand类型,所有的Command可能都实现一个ICommand接口,而这个接口里有一个Run方法:

   1: public interface ICommand
   2: {
   3:     void Run();
   4: }
   5:  
   6: public class EditCommand : ICommand
   7: {
   8:     public void Run()
   9:     {
  10:         //code here...
  11:     }
  12: }
  13: public class MenuItem
  14: {
  15:     public string Text{get;set;}
  16:     //主框架的代码里
  17:     ICommand command = null;
  18:     private void MenuItem_Click(object sender, EventArgs e)
  19:     {
  20:             //延迟加载
  21:             if(command == null)
  22:                 command = //通过反射实例化具体的Command类型,这里就是EditCommand
  23:            command.Run();
  24:     }
  25:     public ToolStripMenuItem CreateMenu()
  26:     {
  27:         ToolStripMenuItem menuItem = new ToolStripMenuItem();
  28:         menuItem.Text = this.Text;
  29:         menuItem.Click += MenuItem_Click;
  30:     }
  31: }

这样,就能保证主框架是稳定的了,子功能负责自己的菜单管理,只需要写一个文件就可以了。

当然,实际的框架实现过程中,肯定会碰到各种各样的问题,这只是一个思路。对于WinForm程序而言,你还可以参考一下开源项目:

SharpDevelop 一个开源的IDE

MonoDevelop 从SharpDevelop发展而来,但是现在大变样了

Mono.AddIn由MonoDevelop的插件机制发展出来的一个小插件系统

Composite Application Block 微软模式&实践小组的

还有很多其他,我就没有研究过了。

以上只是我的一个思路,由于WinForm开发的看到不多,我在网上搜WinForm Best Practice也没找到多少资料,所以希望能够在这方面有所讨论。也许能碰撞出一些火花出来。

后话

刚才出去了一趟,在路上又思考了一些问题。

通过上面对模块加载和WinForm架构设计的讨论,总结一下:吉日文中说的这种应用反射的情况并不是因为基于启动效率的问题,而是设计的考量。这个地方跟性能一点关系都没有(在这里对我在老赵博客里开始错误的评论表示道歉),用不用反射启动效率都是这样。

再看看吉日另外一个应用反射的场景:两个类循环引用。我不知道为什么有这样一个设计,如果是遗留代码那你首先应该考虑重构一下,如果实在不能重构,就必须这样,那只有用反射了。所以这个问题也是设计上的问题,跟反射也没啥关系。

还有吉日说的,配置多数据库的场景。老赵说了,这里推崇ORM。即使你不用ORM,我也觉得这是没有必要的。我不知道有多少情况一个正在运行的系统要突然更换不同类型的数据库?即使有这种情况,那么这也属于重大变更,对于这种变更,你完全可以修改代码。还有,针对这种情况,微软已经给出了Best Practice:提供者模式。虽然提供者模式最终还是反射。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/549366.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle分析函数一——函数列表

Oracle 分析函数 Oracle 分析函数——函数列表 SUM &#xff1a; 该函数计算组中表达式的累积和 MIN &#xff1a; 在一个组中的数据窗口中查找表达式的最小值 MAX &#xff1a; 在一个组中的数据窗口中查找表达式的最大值 AVG &#xff1a;…

用MATLAB实现神经网络

一 BP神经网络实现不使用MATLAB神经网络工具箱问题分析MATLAB实现代码运行结果绘制的图像 二 使用MATLAB的神经网络工具箱简易实现BP网络问题分析工具箱中的相关函数一些参考了MATLAB自带的英文手册mapminmax函数newff函数新版本关于nettrainParam的常用属性train函数sim函数 M…

Follow Me:CCIE RS--使用小凡模拟器搭建的CCIE拓扑图

我用小凡模拟器搭建了CCIE LAB 拓扑图有何不对的地方请指正转载于:https://blog.51cto.com/tanfo/216831

非线性最优化(二)——高斯牛顿法和Levengerg-Marquardt迭代

高斯牛顿法和Levengerg-Marquardt迭代都用来解决非线性最小二乘问题(nonlinear least square)。 From Wiki The Gauss–Newton algorithm is a method used to solve non-linear least squares problems. It is a modification of Newtons method for finding a minimum of a …

逆透视变换详解 及 代码实现(一)

逆透视变换详解 及 代码实现&#xff08;一&#xff09; 中主要是原理的说明&#xff1a; 一、世界坐标轴和摄像机坐标轴 从下图中可以看到&#xff0c;世界坐标为(X,Y,Z) 相机坐标为(Xc,Yc,Zc) 而世界坐标变换到相机坐标存在一个旋转矩阵变换R以及一个位移变换T。 根据上图…

C调用C++链接库

C调用C链接库&#xff1a; 1.编写C代码&#xff0c;编写函数的时候&#xff0c;需要加入对C的接口&#xff0c;也就是extern “c" 2.由于C不能直接用"class.function”的形式调用函数&#xff0c;所以C中需要为C写一个接口函数。例如本来要调用student类的talk函数&a…

逆透视变换详解 及 代码实现(二)

根据 逆透视变换详解 及 代码实现(一)的原理 下面我用车上拍摄的车道图像&#xff0c;采用逆透视变换得到的图像&#xff0c;给出代码前我们先看下处理结果。 首先是原始图像&#xff1a; 下图为逆透视变换图像&#xff1a; 下面说具体的实现吧&#xff01;&#xff01; 一、…

[赵星理]《简单男人》--歌曲温暖你的心,激励你前进

简单的男人&#xff0c;简单的歌曲&#xff0c;赵星理《简单男人》送给所有身负家庭责任的人&#xff0c;要让家越来越美&#xff0c;再苦再累也不能后退。加油&#xff01;简单男人词曲&#xff1a;赵星理演唱&#xff1a;赵星理累不累也不许落泪醉不醉苦辣都值得回味要让家越…

SCVMM

通过SCVMM实现并管理虚拟机高可用性 1、 添加群集主机2、 创建虚拟网络3、 创建虚拟机并实现高可用性接着上一篇文章&#xff0c;这次我们来看一下&#xff0c;如果通过SCVMM R2来实现虚拟机的高可用性。首先将群集主机添加到SCVMM 1、 登陆到计算机Win2008R2&#xff0c;打开S…

序列化包含多种不明类型的集合

序列化包含多种不明类型的集合 代码&#xff1a;/Files/zhuqil/Kirin.rar 导言: 你是否曾经想过序列化构造对象&#xff0c;它里面有一个集合&#xff0c;这个集合包含接口或者抽象类&#xff1f;你是否不知道所有的你要序列化的类型&#xff1f;好吧&#xff0c;如果这样&…

修改EIGRP 路径cost 值,以及分析和实现等价与非等价负载均衡

一、拓扑图&#xff1a;二、配置各路由器的IP和EIGRP 协议&#xff0c;并保证邻接关系的形成。1、我要达到的目的是要让R2到192.168.14.0/24这个网段能在R2和R1断开之后&#xff0c;形成网网络的快速收敛。因为根据EIGRP 的次优路径进拓扑关系的形成条件是要满足FC&#xff08;…

Ubuntu 9.10 升级到ext4

最近一直在使用ubuntu系统&#xff0c;当时升级到9&#xff0c;04的时候&#xff0c;也没有在意系统的文件系统变了&#xff1b;当使用一段时间之后&#xff0c;发现系统没有8.10时使用的顺畅&#xff0c;这时才发现9.04之后心内核都支持ext4文件系统&#xff0c;该文件系统要比…

史上最简单的软件破解——5行脚本代码完美破解99%的过期软件

如果你看到了这篇博文&#xff0c;绝对保证不虚此行。仅仅5行脚本代码&#xff0c;即可破解99%的过期软件。 这件事的背景&#xff1a;最近在找了一些学习资料&#xff0c;其中有Rational Rose画的图&#xff0c;好久没用过它了。今天安装好&#xff0c;导入许可文件&#xff…

数据在链路层传播相关时间计算

本来很懵逼的 看到这篇文章基本全懂了 一般这种题目会让我感觉很是煎熬&#xff0c;不知道怎么算。终于打通这类题目&#xff0c;总结到这里。 先看这类题目的常见表述&#xff1a;如图所示&#xff0c;图中路由器采用存储–转发的方式&#xff0c;所有链路的传播速率均为100…

高等数学的函数连续,可导,可微和偏导数连续的关系(多元)

最近在自学机器学习 顺便把高数捡回来 结论&#xff08;一元函数范畴内&#xff09; 可导与连续的关系&#xff1a;可导必连续&#xff0c;连续不一定可导&#xff1b; 可微与连续的关系&#xff1a;可微与可导是一样的&#xff1b; 可积与连续的关系&#xff1a;可积不一定连续…

在控制台中实现“单词竞猜”游戏 C# 猜词游戏

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/u011528448/article/details/24670471 </div><link rel"stylesheet" href"https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_v…

byvoid 神牛的tarjan算法讲解!

[有向图强连通分量] 在有向图G中&#xff0c;如果两个顶点间至少存在一条路径&#xff0c;称两个顶点强连通 (strongly connected)。如果有向图G的每两个顶点都强连通&#xff0c;称G是一个强连通图 。非强连通图有向图的极大强连通子图&#xff0c;称为强连通分量 (strongly …

关于NLP你还不会却必须要学会的事儿—NLP实践教程指南第一编

作者 | Dipanjan (DJ) Sarkar 编译 | 姗姗 出品 | 人工智能头条&#xff08;公众号ID&#xff1a;AI_Thinker&#xff09; 【人工智能头条导读】在研究和处理自然语言处理的很多问题时&#xff0c;除了关注各种各样基础的数据&#xff0c;高级的深度学习模型、算法外&#x…

ORACLE中表死锁的处理

在进行数据库管理的过程中,经常会出现数据表被用户的一些不合理操作而导致表被锁定的情况,以下主要介绍如何查找哪些表被哪个用户所锁定,以及如何解除锁定: 1.查找被锁定的表: select object_name,session_id,os_user_name,oracle_username,process,locked_mode,status from v$…

asp.net文件上传进度条控件(破解版~没有时间限制) 多项自定义

原版只能用30天&#xff0c;这个破解版可以长期用了&#xff08;设置了时间2010-2110&#xff09;. 注册控件&#xff1a;<% Register TagPrefix"fup" Namespace"OboutInc.FileUpload" Assembly"FileUpload" %>调用控件&#xff1a;<fo…