C# 基础知识系列文章索引

清理GR的加星标项目。分享来自博客园 zhili 的C#基础系列文章。 C#基础知识系列终于告了一个段落了, 本系列中主要和大家介绍了C#1.0到C# 4.0中一些重要的特性,刚开始写这个专题的初衷主要是我觉得掌握了C#这些基础知识之后,对于其他任何的一门语言都是差不多的,这样可以提高朋友们对其他语言的掌握,以及可以让大家更加迅速地掌握.NET的新特性, 并且相信这个系列对于找工作的朋友也是很有帮助的,因为很多公司面试都很看重基础知识是否扎实,是否对C#有一个全面的认识和理解,所以很多公司面试都会问到一些C#基础概念的问题,例如,经常面试会问:你是如何理解委托的,如何理解匿名函数等问题。 然而这个系列中并没有介绍COM互操作性的内容以及.Net 4.5中的一些新特性,所以后面将会对这两个方面的内容进行补充,由于这个系列托的太久了(大概也有3个月吧),所以就先告一段落的,后面将会带来.NET互操作性系列的介绍。下面就为这个系列文章做一个索引,方便大家收藏和查找。 C#基础知识系列索引 C#1.0 1. 深入解析委托——C#中为什么要引入委托 2. 委托本质论 3. 如何用委托包装多个方法——委托链 4. 事件揭秘 5. 当点击按钮时触发Click事件背后发生的事情 C# 2.0 6. 泛型基础篇——为什么引入泛型 7. 泛型深入理解(一) 8. 泛型深入理解(二) 9. 深入理解泛型可变性 10. 全面解析可空类型 11. 匿名方法解析 12. 迭代器 C# 3.0 13. 全面解析对象集合初始化器、匿名类型和隐式类型 14. 深入理解Lambda表达式 15. 全面解析扩展方法 16. Linq介绍 C# 4.0 17. 深入理解动态类型  从C#的所有特性可以看出,C#中提出的每个新特性都是建立在原来特性的基础上,并且是对原来特性的一个改进, 做这么多的改进主要是为了方便开发人员更好地使用C#来编写程序,是让我们写更少的代码来实现我们的程序,把一些额外的工作交给编译器去帮我们做,也就是很多人说微软很喜欢搞语法糖的意思(语法糖即让编译器帮我们做一些额外的事情,减少开发人员所考虑的事情,使开发人员放更多的精力放在系统的业务逻辑上面。),大家从C# 3中提出的特性中可以很好的看出这点(指的是玩语法糖),C#3中几乎大部分特性都是C#提供的语法糖,从CLR层面来说(指的是增加新的IL指令),C# 3并没有更新什么,C# 4中提出的动态类型又是建立在表达式树的基础上,包括Linq也是建立在表达式树的基础上,所以每个特性都是层层递进的一个关系。相信C#后面提出的新特性将会更加方便我们开发程序,感觉所有语言的一个统一的思想都是——写更少的代码,却可以做更多的事情。但是我们不能仅仅停住于知道怎么使用它,我们还应该深入研究它的背后的故事,知道新特性是如何实现的和原理。用一句说就是——我们要知其然之气所以然,学习知识应该抱着刨根问底的态度去学习,相信这样的学习方式也可以让大家不感到心虚,写出的程序将会更加自信。

现代操作系统的调度

这几天在读《现代操作系统》,想起当时学这门课的时候,并没有感觉那么爽,现在通读这本书,知识的过渡性和结构性令我叹服。感受操作系统的魅力吧。 批处理系统中的调度: 1.先来先服务 2.最短作业优先 只有在所有的作业都可以同时运行(也即同时到达)的情况下,最短作业优先算法才是最优化的。 3.最短剩余时间优先-最短作业优先的抢占式版本。调度算法总是选择剩余时间最短的那个进程运行,注意,运行时间必须提前掌握,当一个新的作业到达时,其整个时间同当前进程的剩余时间做比较,如果更少。就运行新进程。可以使新的短作业获得良好的服务。 交互式系统的调度 1.轮转调度。 最古老,最简单,最公平切使用最广,每个进程被分配一个时间片。如果进程在时间片结束之前阻塞或结束,则CPU立即切换。调度程序只是维护一张可运行进程列表,当进程用完它的时间片后,就被移到队列的末尾。时间片太短会导致进程切换过多,降低CPU效率,设置的太长又引起对短的交互请求的响应时间变长。通常20-50ms算合理。 2.优先级调度 为了防止高优先级进程无休止的运行下去,可以在一个时钟中断里降低当前进程的优先级,如果这导致该进程的优先级低于次高优先级的进程,则切换或者也可以赋予每个进程一个时间片。可以和轮转调度一起工作,设置每个优先级上有多个进程。优先运行高优先级,并未高优先级上的进程按照轮转换着运行,如果高优先级没了。就进入到较低优先级。。。问题是如果不偶尔对优先级进行调整,则可能发生饥饿现象。 3.多级队列 CTSS的设计者发现为CPU密集型进程设置较长的时间片比频繁的分给他们很短的时间片更为高效(减少了交换次数),但长时间的进程又会影响响应时间,方法是设立优先级类,最高优先级类里的进程运行1个时间片。次高运行2个。以此类推。当一个进程用完分配的时间片后,被移动到下一类。大致算法都是用于讨好交互用户和进程,而不惜牺牲后台进程 //故事:可以采用只要终端上有Enter键按下,就将该终端上的进程移到最高优先级类。假设当前进程急需交互,但是。一个人发现了。大家都开始用。。。理论和实际差异太大。。哈哈 4.最短进程优先 这个很好立即,但难点在于如何找出最短的那个。一种方法是根据过去的行为推测。假设每个命令执行时间为T0,下一次运行时间为T1,则可以根据aT0+(1-a)T1来估计时间。。a被用来决定尽快忘掉老的运行时间还是记住它。这种算法成为老化算法。通常选a=1/2 5.保证调度 就是保证每个用户获得cpu的1/n,系统需要跟踪进程的cpu时间,他实际获得如果多于应该获得的。则转向实际获得小于应该获得的。 6.彩票调度 保证调度很难实现,而彩票调度算法是向进程提供各种系统资源的彩票。一旦需要做出一项调度决策时,就随机抽出一张彩票。谁获得谁就上。比如视频服务器,可以为不同的帧速率提供不同的彩票。然后分配cpu 7.公平分享调度 这个就考虑到了进程的所有者。需要我们定义公平的含义。是保证每个用户只占用的时间相等还是其他了。 实时系统的调度: 可以分为硬实时和软实时,前者必须满足绝对的截止时间,后者则可以容忍一些。用户级线程系统是不知道的。用户级和内核级的差异主要在性能,用户级需少量的机器指令,而内核级需要很多的。过程。采用轮转和优先级调度更常见一些。 //操作系统的大神们太强大了。哲学家进餐问题居然可以通过拿起左边叉子以后,检测右边是否可用,如果不可用,则等待一个随机的时间。这种方案是可行的。在极少的情况下不可用。。

不要变成你讨厌的人,面目可憎

本文来自xjp的碎碎念,我很喜欢的一个博主。博客已被伟大的GFW屏蔽。和文章的主题类似,我有时候会在G+上会纠正一些人的谣言,并且给出澄清,可是,往往效果不大。我的态度很简单,你要反对一样东西,请你不要是那样的东西。或用那样的东西去反对。不要为任何主义所迷惑,你要做好一个人。 今天看到一篇来自《新京报》的报道,称时事评论员@周筱赟爆料称,根据铁道部的两份采购合同显示,推测铁道部12306订票网站实际投入已经超过5亿元,而不是之前曾披露的3.2亿元。 首先我很赞同周筱赟所做的事情,在国内目前民众获取信息渠道有限的情况下,有这样的热心人士去披露政府部门行政行为中值得讨论的部分,对于整个社会的公正与透明都有极大的推动作用。 但我注意的是另一群人,他们典型的回复是: 1、花5个多亿做成这么垃圾的网站,铁道部公然贪污多少钱?臭不要脸的!二逼的网站和系统归功于傻逼造就! 2、卧槽,里面有4.5亿是贪污款吧 3、习总说反腐,最大的蛀虫在这里,敢反否? 4、3亿建站为什么这些年一直没有工商部去追查12306的贪污问题。你懂我懂大家懂。 5、中央纪委、监察部和各级纪检监察机关要加大检查监督力度,执好纪、问好责、把好关。 6、太极集团是做医药的呀,怎么也搞起软件来了。我想说,有没经验都不要紧,要紧的是有钱。咱就撒都能做! 7、五亿······· 用了个500的模版 月薪5000水平的制作团队 8、三億各單位部門宣傳費,一億三公支出,五千萬采購合同草擬費用,四千萬給媒體掩口費, 九百九十萬信息產業部備案費用,最後十萬才是網站制作費用… 這五億基本上都使對了地方,沒有錯啊! 其它的评论都是诸如此类,某一些理性的评论都被深埋其中。 我不是铁道部、太极的任何一方,我不能拍着胸脯说这些问题一定不存在,但真正让我恐惧的是,有大量网友没有认真去研究文章的内容与事实,只是单纯下意识地做出了判断,然后开喷。 我们仔细去看我们讨厌的那些五毛与政府宣传部门,他们的日常做法都是: 1、戴帽子 2、站在道德高度,说正确的废话 3、自说自话,完全不管别人在说什么 4、预设立场 5、我永远是对的,反对我的都是错的 6、你们站在人民的对立面 然后有一个微博网友在评论里跟我说,他只需要一万元就能够搞定12306的网站外包开发。听到这样的话,我不由地一阵颤抖,如果这话来自一名所谓的业内人士,那我真的不知道应该怎么说了。 引用某网友的评论: 从专业角度来说,投入不算多,只是透明度不够,民众才疑惑!全国各地还需要再多些大型机房,才能满足高峰期分流排队和并发操作! 我的看法是,不否认铁道部的开发、架构设计存在一定问题,如果没有实际的大型系统设计经验的团队,可能会造成很多理论与实际脱节问题,事实上今年的12306已经比去年好太多了,他们也在吸取教训。当然,我也赞成他们向互联网公司取经,吸收现有经验。 建议大家不要单纯喷,5亿这个数字可能略高,但比起数千万的静态网站好多了,至于具体审计是国家审计局的事情,我支持惩处贪腐。做一个覆盖数千万用户,承受刷票插件5秒一次的并发,服务器、带宽、配套都是成本。而售票数字化几乎是必经之路,铁道部走出这一步是好的,买不到票有基础运力的问题,跟网络售票无关。 不要一叶障目,买不到票人人都会烦心,诚然铁道部是一个不错的发泄口,但如果只是为了喷而喷。借用我之前的一句话,铁道部如何做你们才满意?

社工字典生成工具

在家无聊写了这个工具,主要是为了防止自己这一直写随笔把本行忘了。。也熟悉一下代码。。暂时不放源代码了。以后改的好一点再发吧。 作者:bystander 博客:http://leaver.me 转载请注明出处!   涉及到的东西有: 1.C#隐藏TabControl的header部分,前面的文章有介绍 2.获取窗体全部的某一类控件(这个无聊的话抽象出一个通用的方法出来,以后就可以直接用了)

C#隐藏TabControl标签栏

今天考过了微软的那个70-562和70-536的考试。然后下午把软件体系结构的作业做了。然后看了一下栈溢出,我博客首页右侧的那个就是我的栈溢出id了。。 然后就看到了这个问题。这个问题。我曾经遇到过。貌似大家知道比较多的是两种。第一种就是设置大小。 但是这样你注意看的话,左上角有个小的瑕疵。这个没办法的。。还有一种比较低级但还算有效的方法就是在设计的时候将TabControl向上移动。运行以后就会遮住了。 我当时不过取巧了。好像就用的第二种。。今天看到这个题目的时候,就做了下标记。刚才去看。大牛已经给出答案了。就是自己继承一个TabControl控件。重写 方法,在方法里拦截系统消息。 具体用法。就是在你的项目里新建一个类文件。然后把上面的代码拷进去。然后编译一下。就会在工具箱里多出一个TablessControl控件。拖进来即可使用。当然你也可以自定义一个用户控件。都不是事。这个控件设计时标签页可见。运行时由于拦截了信息消息。标签栏就不可见了。堪称完美。。

图的遍历(C#)

讲的非常好的一篇文章。感谢abatei,直接收藏分享之。 图的存储结构 图的存储结构除了要存储图中各个顶点的本身的信息外,同时还要存储顶点与顶点之间的所有关系(边的信息),因此,图的结构比较复杂,很难以数据元素在存储区中的物理位置来表示元素之间的关系,但也正是由于其任意的特性,故物理表示方法很多。常用的图的存储结构有邻接矩阵、邻接表、十字链表和邻接多重表。 8.2.1 邻接矩阵表示法 对于一个具有n个顶点的图,可以使用n*n的矩阵(二维数组)来表示它们间的邻接关系。图8.10和图8.11中,矩阵A(i,j)=1表示图中存在一条边(Vi,Vj),而A(i,j)=0表示图中不存在边(Vi,Vj)。实际编程时,当图为不带权图时,可以在二维数组中存放bool值,A(i,j)=true表示存在边(Vi,Vj),A(i,j)=false表示不存在边(Vi,Vj);当图带权值时,则可以直接在二维数组中存放权值,A(i,j)=null表示不存在边(Vi,Vj)。 图8.10所示的是无向图的邻接矩阵表示法,可以观察到,矩阵延对角线对称,即A(i,j)= A(j,i)。无向图邻接矩阵的第i行或第i列非零元素的个数其实就是第i个顶点的度。这表示无向图邻接矩阵存在一定的数据冗余。 图8.11所示的是有向图邻接矩阵表示法,矩阵并不延对角线对称,A(i,j)=1表示顶点Vi邻接到顶点Vj;A(j,i)=1则表示顶点Vi邻接自顶点Vj。两者并不象无向图邻接矩阵那样表示相同的意思。有向图邻接矩阵的第i行非零元素的个数其实就是第i个顶点的出度,而第i列非零元素的个数是第i个顶点的入度,即第i个顶点的度是第i行和第i列非零元素个数之和。 由于存在n个顶点的图需要n2个数组元素进行存储,当图为稀疏图时,使用邻接矩阵存储方法将出现大量零元素,照成极大地空间浪费,这时应该使用邻接表表示法存储图中的数据。 8.2.2 邻接表表示法 图的邻接矩阵存储方法跟树的孩子链表示法相类似,是一种顺序分配和链式分配相结合的存储结构。邻接表由表头结点和表结点两部分组成,其中图中每个顶点均对应一个存储在数组中的表头结点。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。如图8.12所示,表结点存放的是邻接顶点在数组中的索引。对于无向图来说,使用邻接表进行存储也会出现数据冗余,表头结点A所指链表中存在一个指向C的表结点的同时,表头结点C所指链表也会存在一个指向A的表结点。 有向图的邻接表有出边表和入边表(又称逆邻接表)之分。出边表的表结点存放的是从表头结点出发的有向边所指的尾顶点;入边表的表结点存放的则是指向表头结点的某个头顶点。如图8.13所示,图(b)和(c)分别为有向图(a)的出边表和入边表。 以上所讨论的邻接表所表示的都是不带权的图,如果要表示带权图,可以在表结点中增加一个存放权的字段,其效果如图8.14所示。 【注意】:观察图8.14可以发现,当删除存储表头结点的数组中的某一元素,有可能使部分表头结点索引号的改变,从而导致大面积修改表结点的情况发生。可以在表结点中直接存放指向表头结点的指针以解决这个问题(在链表中存放类实例即是存放指针,但必须要保证表头结点是类而不是结构体)。在实际创建邻接表时,甚至可以使用链表代替数组存放表头结点或使用顺序表存代替链表存放表结点。对所学的数据结构知识应当根据实际情况及所使用语言的特点灵活应用,切不可生搬硬套。 【例8-1 AdjacencyList.cs】图的邻接表存储结构 l Vertex类中包含了一个visited成员,它的作用是在图遍历时标识当前节点是否被访问过,这一点在稍后会讲到。 l 邻接点指针域adjvex直接指向某个表头结点,而不是表头结点在数组中的索引。 AdjacencyList<T>类中使用了一个泛型List代替数组来保存表头结点信息(第5行代码),从而不再考虑数组存储空间不够的情况发生,简化了操作。 由于一条无向边的信息需要在边的两个顶点分别存储信息,即添加两个有向边,所以58~78行代码的私有方法AddDirectedEdge()方法用于添加一个有向边。新的邻接点信息即可以添加到链表的头部也可以添加到尾部,添加到链表头部可以简化操作,但考虑到要检查是否添加了重复边,需要遍历整个链表,所以最终把邻接点信息添加到链表尾部。 【例8-1 Demo8-1.cs】图的邻接表存储结构测试 B:AD C:A D:AB  本例存储的表如图8.12所示,结果中,冒号前面的是表头结点,冒号后面的是链表中的表结点。 8.3 图的遍历 和树的遍历类似,在此,我们希望从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历(TraversingGraph)。如果只访问图的顶点而不关注边的信息,那么图的遍历十分简单,使用一个foreach语句遍历存放顶点信息的数组即可。但如果为了实现特定算法,就需要根据边的信息按照一定顺序进行遍历。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。 图的遍历要比树的遍历复杂得多,由于图的任一顶点都可能和其余顶点相邻接,故在访问了某顶点之后,可能顺着某条边又访问到了已访问过的顶点,因此,在图的遍历过程中,必须记下每个访问过的顶点,以免同一个顶点被访问多次。为此给顶点附设访问标志visited,其初值为false,一旦某个顶点被访问,则其visited标志置为true。 图的遍历方法有两种:一种是深度优先搜索遍历(Depth-First Search 简称DFS);另一种是广度优先搜索遍历(Breadth_First Search 简称BFS)。 8.3.1 深度优先搜索遍历 图的深度优先搜索遍历类似于二叉树的深度优先搜索遍历。其基本思想如下:假定以图中某个顶点Vi为出发点,首先访问出发点,然后选择一个Vi的未访问过的邻接点Vj,以Vj为新的出发点继续进行深度优先搜索,直至图中所有顶点都被访问过。显然,这是一个递归的搜索过程。 现以图8.15为例说明深度优先搜索过程。假定V1是出发点,首先访问V1。因V1有两个邻接点V2、V3均末被访问过,可以选择V2作为新的出发点,访问V2之后,再找V2的末访问过的邻接点。同V2邻接的有V1、V4和V5,其中V1已被访问过,而V4、V5尚未被访问过,可以选择V4作为新的出发点。重复上述搜索过程,继续依次访问V8、V5。访问V5之后,由于与V5相邻的顶点均已被访问过,搜索退回到V8,访问V8的另一个邻接点V6。接下来依次访问V3和V7,最后得到的的顶点的访问序列为:V1→ V2→ V4→ V8→ V5→ V6→ V3→V7。 下面根据上一节创建的邻接表存储结构添加深度优先搜索遍历代码。 【例8-2 DFSTraverse.cs】深度优先搜索遍历 打开【例8-1 AdjacencyList.cs】,在AdjacencyList<T>类中添加以下代码后,将文件另存为DFSTraverse.cs。 private void InitVisited() //初始化visited标志 { foreach (Vertex&lt;T&gt; v in items) { v.visited = false; //全部置为false } }</pre> V1 V2 V4 V8 V5 V6 V3 V7  本例参照图8-15进行设计,运行过程请参照对图8-15所作的分析。 8.3.2 广度优先搜索遍历 图的广度优先搜索遍历算法是一个分层遍历的过程,和二叉树的广度优先搜索遍历类同。它从图的某一顶点Vi出发,访问此顶点后,依次访问Vi的各个未曾访问过的邻接点,然后分别从这些邻接点出发,直至图中所有已有已被访问的顶点的邻接点都被访问到。对于图8.15所示的无向连通图,若顶点Vi为初始访问的顶点,则广度优先搜索遍历顶点访问顺序是:V1→V2→ V3→ V4→ V5→ V6→ V7→ V8。遍历过程如图8.16的所示。 和二叉树的广度优先搜索遍历类似,图的广度优先搜索遍历也需要借助队列来完成,例8.3演示了这个过程。 【例8-3 BFSTraverse.cs】广度优先搜索遍历 打开【例8-2 DFSTraverse.cs】,在AdjacencyList<T>类中添加以下代码后,将文件另存为BFSTraverse.cs。  V1 V2 V3 V4 V5 V6 V7 V8  运行结果请参照图8.16进行分析。 8.3.3 非连通图的遍历 以上讨论的图的两种遍历方法都是相对于无向连通图的,它们都是从一个顶点出发就能访问到图中的所有顶点。若无向图是非连通图,则只能访问到初始点所在连通分量中的所有顶点,其他连通分量中的顶点是不可能访问到的(如图8.17所示)。为此需要从其他每个连通分量中选择初始点,分别进行遍历,才能够访问到图中的所有顶点,否则不能访问到所有顶点。为此同样需要再选初始点,继续进行遍历,直到图中的所有顶点都被访问过为止。 上例的代码只需对DFSTraverse()方法和BFSTraverse()方法稍作修改,便可以遍历非连通图。

SQL注入中的WAF绕过技术

作者:bystander 博客:http://leaver.me 论坛:法克论坛 目录 1.大小写绕过2.简单编码绕过3.注释绕过4.分隔重写绕过5.Http参数污染(HPP) 6.使用逻辑运算符or /and绕过7.比较操作符替换8.同功能函数替换9.盲注无需or和and 10.加括号11.缓冲区溢出绕过 1. 大小写绕过这个大家都很熟悉,对于一些太垃圾的WAF效果显著,比如拦截了union,那就使用Union UnIoN等等。绕过 2. 简单编码绕过比如WAF检测关键字,那么我们让他检测不到就可以了。比如检测union,那么我们就用%55 也就是U的16进制编码来代替U, union写成 %55nION,结合大小写也可以绕过一些WAF,你可以随意替换一个或几个都可以。。 也还有大家在Mysql注入中比如表名或是load文件的时候,会把文件名或是表明用16进制编码来绕过WAF都是属于这类。 3. 注释绕过这种情况比较少,适用于WAF只是过滤了一次危险的语句,而没有阻断我们的整个查询 4. 分隔重写绕过还是上面的例子,适用于那种WAF采用了正则表达式的情况,会检测所有的敏感字,而不在乎你写在哪里,有几个就过滤几个。。 我们可以通过注释分开敏感字,这样WAF的正则不起作用了,而带入查询的时候并不影响我们的结果 再给出一个例子说明用法 6. 使用逻辑运算符 or /and绕过7. 比较操作符替换包括!= 不等于,<>不等于,< 小于,>大于,这些都可以用来替换=来绕过, 比如上一个例子,要判断是不是74,假设=被过滤,那么我们可以判断是不是大于73,是不是小于75,然后就知道是74了。。很多WAF都会忘了这个。 8. 同功能函数替换Substring()可以用mid(),substr()这些函数来替换,都是用来取字符串的某一位字符的。 Ascii()编码可以用hex(),bin(),也就是16进制和二进制编码替换 Benchmark() 可以用sleep()来替换,这两个使用在基于延时的盲注中,有机会给大家介绍 如果连这些都屏蔽了,还有一种新的方法 9. 盲注无需or和and比如有这样一个注入点: 10. 加括号11.缓冲区溢出绕过刚刚写着把这个给忘了。这个是从国外一个博客看到的。

远程管理Demo(C#)

一个C#的通信的例子 1.服务端,服务端通过ip和端口生成客户端之后,点击开始监听后,便开启监听线程持续监听,同时注册断开连接和收到信息的事件。收到来自TcpClient 流中的信息后,解析之,如果是连接信息,就添加到连接列表,这样服务端就可以显示多个客户端了。如果是断开信息,就删掉。如果服务端想要给客户端发消息,就选中该客户,然后填写信息,就会调用连接类的发送方法。  2.客户端,也就是被控端,被控端通过tcp连接到远端ip,然后发送连接成功状态,随后异步读取。读取到信息后调用解析方式。然后处理。。 3.服务端如何生成客户端。其实也比较简单。就是写好客户端以后,保存为文本。然后通过CodeDomProvider的相关方法来编译即可。代码如下:

Lambda高手之路第六部分

今天武汉地铁通车了,今天介绍一些新的Lambda设计模式,应该是最后一部分了。 本节介绍一些核心有lambda表达式的模式,我不认为他们完全是新的模式,但是至少我还没有看到有人给他们起过名字,我于是决定尝试取个可能好,也可能不好的名字,这样我起码能很容易的给别人描述,有话在先,许多模式相当强大,但是可能会引入潜在的bug,所以小心为上 复杂的多态 Lambda表达式也可以被用来创建一些多态(override),而不用使用abstract或者virtual关键字(当然这并不意味着就不能用),考虑如下的代码片段 看起来没什么新的知识,我们创建一个类,里面有一个属性(一个lambda表达式),又一次JavaScript化了,有趣的地方是:属性暴露的这个部分不只是本类可以改变,子类也可以改变,看代码 看到了。我们可以改变这个方法。或者进行更精确的操作,这种方法的缺点是我们不能直接访问父类的实现,也就缺乏了基类的能力,因为,这个父类的属性会有同样的值,如果程序员真的需要这样写,我建议你遵循 pattern 这样的话,子类就不得不拥有了 AddSomeAction() 方法,而这个方法是吧当前的方法压入堆栈,那样我们可以恢复之前的状态。 这种模式我起了一个名字叫做Lambda属性多态模式(LP3),它简单的描述了可以在属性里捕获任何方法。之后可以被子类所设置,栈是这个模式的一个附加品,没有改变我们使用属性来完成的模式目标 为什么要用这种模式?有几个理由。地一个,因为我们可以用。但是等一等。如果你使用当中不同的属性,这个模式会变得相当棘手,突然,多态变成了一个完全的新方法。但是这也许是一个不同的模式,现在我想说这个模式完成了以前人们认为不可能的事情 举个例子,你想要(不建议,但是也许对该问题是最优雅的解决方法了。)重写一个静态方法,好吧。静态不可能被继承,原因很简单,师承是对实例对象来说的。而静态方法不属于任何一个实例,对于所有的实例都是一样的。这会引发一个警告,下面的例子也许并不如你所想的结果,因此,除非你非常清楚。否则不要乱用。 看代码 这很简单,希望没有对你产生误导,这种模式有时候会让事情变得异常复杂,这也是为什么我总是避免使用它。不过他很有用。(可以通过该方法构造所有的静态属性和方法,并且可以使你总是获得你感兴趣的那个)只要你不感到头疼,这是解决静态多态性的一个好方法。是的。静态多态性是可能的。 简单请求一个方法 之前我已经介绍过这个方法了。但是我没有说名字,这就是方法字典模式,这个模式的一个基础就是一个哈希表或是一个字典,包含一个keys(通常是字符串,但取决于具体的情况),这些keys对应一些特定的方法,这个模式也指定了一个特殊的方法构造这些字典,否则,一个简单的switch-case就搞定了,看代码 这哪里需要字典?好像不需要。事实上我们写的更好一些。 等等,这个模式现在没有优点了。。事实上,这个模式并不特别好写,她还需要多写写代码,但是我们可以使用反射来自动化这个字典的构造,这样我们就会和switch-case一样搞笑了。但是我们的代码更加健壮,并且维护更简单,如果你写switch-case。。你就需要手工添加很多分支语句了。。 我们看一种可能的实现方法。我通常更倾向于添加一些类型转换,这样就可以方便的使用keys对应的值了。当然,你也可以通过其他方法实现,比如使用一致的方法签名,这里我还是用转换。 现在看起来好多了,事实上。这个模式节省了我很多时间。这个模式最好的就是:它使你可以写出优雅的插件。通过不同的库扩充功能。为什么。你可以使用该方法来扫描未知的库,这些库符合一些确定的模式。然后包含他们进入你的代码,这样。没有任何问题。其他库的方法就会继承成你的代码里。你所需要做的仅仅如下: 现在,我们所需要做的就是确定加载的插件,并且添加一些方法来处理这些事事情。最后。可以通过调用LoadPlugin()方法从给定的程序集实例上加载方法。这只是这个模式的一个应用。而我其实还可以做很多。。。比如我们也在JavaScript里面使用。那里可是没有内置的反射的。。