社工字典生成工具

在家无聊写了这个工具,主要是为了防止自己这一直写随笔把本行忘了。。也熟悉一下代码。。暂时不放源代码了。以后改的好一点再发吧。 作者:bystander 博客:http://leaver.me 转载请注明出处!   涉及到的东西有: 1.C#隐藏TabControl的header部分,前面的文章有介绍 2.获取窗体全部的某一类控件(这个无聊的话抽象出一个通用的方法出来,以后就可以直接用了)  3.文件操作 4.字符串操作 反正很简单,主要就是写的时候思路要清晰。知道大部分使用密码的规则。处理一下生日格式。否则后面很麻烦。。相应的验证也比较少。界面依然毫无美感。。 总结: 现在发现在控件命名上越来越顺利了。自我感觉良好。后面慢慢的要开始尝试使用学到的一些新的技术点。。 下载:社工字典生成工具

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的相关方法来编译即可。代码如下: 源码下载:CSharp RAT Example.zip

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里面使用。那里可是没有内置的反射的。。

Lambda高手之路第五部分

武汉下雪了。。今天介绍Lambda表达式非常有用的情况。。ps:这个高手之路已经翻译了10000多字了。。疼啊。。 一些模式比另一些模式有时候更加合适,真正有用的模式是自定义方法表达式,用爱促使话一些对象的部分,我们考虑下面这种情况。 我们想要创建一个可以处理多种延迟加载的对象,这意味着即时对象已经被实例化了,我们还没有加载所有请求的资源,一个理由就是防止大量的IO操作。(比如通过网络传输),当我们开始使用数据的时候,我们想要确定数据足够新鲜,现在有一些确定的方法可以做这个。并且最有效的显然是实体框架已经用LINQ解决了延迟加载的问题,Iqueryable仅存储了查询,而没有任何无关的数据。一旦我们请求一个结果。不仅仅构造的查询被执行,同时也被以更高效的方式执行,比如一个在远程数据服务器上的SQL查询。 在这里,我们仅仅想要看看两种情况的不同点,首先,我们查询,一切就绪,查询应该在已经加载了的数据上进行。 简单来看,这里我们有两种不他哦你的方法,地一个是我们把数据从数据库里提取出来(也就是Database静态类所做的),然后第二个方法将会过滤从数据库里提取出来的数据。一旦我们将会从我们的第一次查询取得结果,当然我们也可以构造内置的其他方法来重置类的行为,对于工业级的代码,其他的方法也许更加有用。 另一个例子是初始时间分支,假设我们有一个对象,该对象有个方法叫做Perform(),这个方法可以用来调用一些代码,包含这个方法的对象可以被初始化,初始化有三种方式。 通过传递方法来调用 通过传递一些包含这个方法的对象来调用 或者通过传递第一种情况下的序列化以后的信息来调用。 现在我们可以保留所有的三种方式做全局变量。而Perform方法将不得不查看当前的状态(或者是保存在枚举变量里,或者和null进行比较)然后检测被调用的正确的方式,最后调用开始。 更好的一种方法是吧Perform()方法写成一个属性,这个属性仅仅允许在类里面进行set,它是一个委托类型,现在我们可以在对应的构造方法里面直接设置这个属性,因此,我们可以不用全局变量,也不用担心这个对象是如何实例化的,这种方法更好。 看一小段简单的代码。 即时这个例子看起来如我们所愿被构造了。让阿尔。大多数情况下只使用前两种,但是随着领域特性语言,编译器,日志框架,数据访问层和其他很多情况下,通常有很多方式可以完成,但Lambda表达式也许是最优雅的。 考虑这种情况,我们可以在函数编程领域体会到即时调用方法表达式的好处,我们可以看到C#中IIFE的一种用法。用的不多。但是我认为真的很好。但不是用在这种情况下。 我们也可以使用即时调用方法来防止一些确定的非静态的方法被重复调用。这就会出现自定义方法和初始时间分支和IIFE的组合使用了。 下一节介绍一些新的Lambda设计模式

Lambda高手之路第四部分

首先祝大家平安夜快乐。本篇介绍一些流行的JavaScript模式。为下一篇打基础 使用/了解JavaScript的一个好处就是函数的高级用法。。在JavaScript里。函数仅仅是对象。他们可以有赋给他们的属性。而在C#中。我们不能做我们可以在JavaScript的全部事情。但是我们仍然可以做些事情。一个原因是JavaScript在函数里给变量以作用域。因此,不得不通过创建函数,大多数情况是匿名的来定位变量。而在C#中。通过使用块,通过花括号来创建作用域 当然,换种方式来说。C#中,函数也会给变量作用域。通过使用Lambda表达式。我们通过花括号在其里面创建了一个变量。然而。我们也可以局部的创建作用域。 我们来看看通过使用Lambda表达式可以实现一些在JavaScript里面有用的模式把。 回调模式 这个模式是个老的模式。事实上。回调模式从.net 的第一版就开始使用了。但是是以一种很简单的方式实现的。而现在。通过使用Lambda表达式。闭包,捕获变量等特性能够允许我们写出如下的代码来。 对于JavaScript程序员会觉得这没什么啊。他们使用这个模式太多了。然而,它非常有用。因为我们可以使用参数作为Ajax相关事件的事件处理器(比如oncompleted,onsuccess),等等。如果你使用LINQ,那么你可能也会用到回调模式的一些东西。举个例子。LINQ的where子句将会在每一次迭代中回调你的查询语句。这只是回调函数的一个例子。在.net的世界里。事件如它名字所暗示的那样。通常是事件处理的首选方法。这有时候很像一个回调。他有两个参数。有一个特殊的关键字和一个类型模式(两个参数分别是sender和arguments,sender通常是object类型。Arguments通常继承自EventArgs) 可以通过+= 和-=给事件添加/删除事件处理程序。 返回方法 和普通的方法比较。Lambda表达式也可以返回一个方法指针(就是一个委托实例),这意味着我们可以使用Lambda表达式创建/返回一个lambda表达式(或者今年仅是一个已定义好的方法的委托实例),大量的情况下。这个模式也很有用。首先看一下例子。 代码本应该更短些。我们可以让default如果请求的语言没有找到。只是抛出一个异常即可。不过。这个例子展示了这是一种方法工厂。另一种同等效果的方法是包含一个Hashtable。或者更好的话用Dictionary<K, V> 即使这看起来似乎有点过度工程化了。但是也许这是方法工厂最好的例子了。毕竟方法简单易扩展,可以被用在很多情况下。这中模式和反射的组合可以是的程序代码更松耦合,更易使用。并且代码更健壮。下图展示了模式的工作流程 自定义方法 自定义方法模式一个JavaScript中普遍的技术。可以用在代码中提高性能和健壮性,这种模式的背后思想是方法被设置为一个属性。于是可以和其他方法非常方便的交换。我们看一下具体的代码 这段代码做了什么?好吧。第一种情况下,我们得到第一个素数。也就是2.虽然这很显而易见。我们可以体征我们的算法默认来排除掉所有的偶数。这就加速我们的算法。但是我们依然能够得到开始的偶素数2.我们就可以通过调用NextPrime方法来获得素数了。我们就可以在第二部分里有话我们的算了。 我们已经看到这种写法可以优化性能。我们可能一下这个例子 这里我们有了两根分开的区域。一个是为钱1000个数准备的。其他的则留在了另一个区域。通常我们可能需要区分这两种情况。这就是我们为什么使用了自定义方法,当小区域执行完后,自定义函数就会改变了。来执行大的区域了。 即时执行方法表达式 在JavaScript中即时执行方法表达式也叫做IIFEs,也相当普遍。这是因为在JavaScript中,不像C#中的花括号可以构造一个局部变量。因此一个变狼可能会污染一个全局对象。(最有可能就是一个window对象),由于很多原因,这种情况很不好。。 解决方法也很简单,当花括号不能给一个作用域的时候,方法却可以。因此,定义在方法里面的变量就被限制在这个方法里。就像是他的孩子一样。因此,通常JavaScript用户想让那些方法立刻执行。否则,是对变量名和语句行的浪费。另一个原因就是这个方法只执行一次。 在C#中我们也可以写出类似的方法。我们也会得到一个新的作用域。但这不是我们主要关心的。因为我们可以随心所欲创建新的作用域,我们看些例子 这段代码很容易理解。然后,如果我们想要传一些参数时候。我们需要定义他们的类型你个,我们看一下如何给即时执行方法传递参数 看上去似乎没做什么。然而。我们可以和async关键字组合起来。我们看 Ok了。 即时对象初始化 我把这个模式放在关于Lambda表达式的文章里是因为匿名对象比我们刚刚的一些简单的例子能表达的要多得多。其中一个就是匿名对象也可以包含Lambda表达式。这可以作为我写在本文里的理由。 如果你想要运行这个模式,你可能会看到一个异常。。至少我看到了。。这难以理解的理由是Lambda表达式不能被赋给匿名对象。如果你也没明白。。那我们看来是坐在一条船上的。 幸运的是,编译器已经告诉我们了。“哥们,我不知道我该为你的那个Lambda表达式创建哪种类型的委托啊”我们可以帮一下编译器。如下所示。 一个问题就产生了。方法(这里是Ask)存活的作用域是什么?答案是他存活在创建匿名对象的类里面,或者如果他使用了捕获变量,就在他自己的作用域里面。因此,编译器仍然创建了一个匿名对象(包含对编译器生成的类的元数据,实例化了一个有着类信息的新的对象),但是只是设置了委托对象Ask属性 注意:你应该避免使用这个模式,当你真的想要访问一个匿名对象的所有属性的时候。理由如下:C#编译器请求在你使用每一个对象之前,应该首先声明他。因此,用的地方一定在声明之后,但是编译器怎么知道?在编译器看来。Person变量还没声明完呢。就开始使用了。 所以,在上面那个Lambda表达式里并不能直接访问person的Name和Age属性 有一个方法跳出这个陷阱(事实上有很多种,但我只喜欢这一种最优雅的,考虑下面这段代码 现在因为我们之前已经声明了,我们也可以说明person为object对象。但是这样的话我们就要用到反射机制了(可能还需要一些漂亮的包装器),来访问匿名对象的属性,在这种情况下,我们依赖于DLR,他会对这种情况出现一个最漂亮的包装器,现在这段代码就非常JavaScript化了,我也不知道是好还是坏,这也就是为什么我说这个是一个注意点。。 初始时间分支 这个模式事实上和自定义方法非常接近,唯一的不同,这种情况下,该方法并不定义自己,而是包含其他方法。显然是可能的。如果这个“其他方法”不是通过传统的方式定义,而是通过属性,(成员变量) 这种模式的别名也叫做加载时分支,是一个优化模式,这个模式用来避免switch-case或if-else语句等控制结构的大量使用。也可以理解为这个模式为代码永久性的创建了确定分支之间的连接。 考虑下面这个例子 我们都做了什么呢?首先我们有一个方法读取用户配置(由一个配置Setting类来保存),如果我们发现启用了自动设置。我们就给AutoSave这个属性赋上全部的代码,否则我们就放一个空方法在这里,而们就可以通过调用AutoSave()一次就行了,不再需要检查配置设置或其他的什么情况了。我们也不需要保存一个特殊的布尔变量,因为对应的方法已经被动态的设置了。 有人也许认为这不是一个巨大的性能提高,但是这仅仅是一个小例子,在一些复杂的代码里,这会节省很多时间,尤其是代码越来越复杂的情况下。 另外(我认为这是最主要的原因),代码更加容易维护(如果你了解这个模式的话)没有了不必要的控制逻辑,程序员可以更加专注于重要的东西—调用这个自动保存的具体操作 在JavaScript中,像初始时间分支模式被用在很多性能检测上(比如浏览器检测)不去管浏览器检测实际上是很邪恶的,并且不应该在任何网页上检测用户的浏览器, 性能检测非常有用,通常和这种模式一起组合使用,这也是Jquery用来对Ajax请求检测需要的正确对象的方法。 下一部分介绍Lambda表达式超级有用的情况,同样圣诞节快乐。

Lambda高手之路第三部分

背后的秘密-MSIL 通过著名的LINQPad,我们可以更深入的查看MSIL代码而没有任何秘密。下图是一个LINQPad的使用截图 我们会看三个例子,第一个Lambda表达式如下: 对应的普通函数是这样的 生成的MSIL代码片段如下: 最大的不同是方法的名称用法不同。而不是声明。事实上。声明是完全一样的。编译器在类里面创建了一个新的方法来实现这个方法。这没什么新东西,仅仅是为了我们使用Lambda表达式方便代码编写。从MSIL代码中,我们做了同样的事情。在当前对象里调用了一个方法。 我们在下图里演示一下编译器所做的修改。在这个图例。我们可以看到编译器把Lambda表达式移动成了一个固定的方法。 第二个例子将展示Lambda表达式真正的奇妙之处,在这个例子里。我们既使用了有着全局变量的普通方法也使用了有捕获变量的Lambda表达式。代码如下 没什么不同的似乎。关键是:lambda表达式如何被编译器处理 和第一个例子一样。机制相同。编译器把lambda表达式移动到一个方法里。但是不同的是,编译器这次还生成了一个类。编译器为我们的lambda表达式生成的方法会放在类里,这就给了捕获的变量一个全局的作用域,通过这样。Lambda表达式可以访问局部变量。因为在MSIL里。它是类实例里面的一个全局变量。 所有的变量因此就可以在新生成的类的对象里赋值/读取了。这解决了变量之间的引用问题。(其实就是只保留了对该类实例的引用。)编译器也足够智能之会把这些捕获的变量放到类里面。因此,当我们使用Lambda的时候才没有太大的性能问题。无论如何。注意。由于保持了对lambda表达式的引用,因此可能造成内存泄漏。只要方法还在。变量就仍然存活。显而易见。而现在我们知道了原因。 我们再次用图示来说明。这这种闭包情况下里。不仅仅方法会被移动。捕获的变量也会被移动。所有被移动了的对象会被放到一个新生成的类里。因此一个没有名称的类就隐式的出现了。 下一节将是映射流行的JavaScrpit模式。

Lambda高手之路第二部分

闭包的影响 为了展示闭包的影响,我们看下面这个例子。 这个问题很怪,我在我的JavaScript课程上经常问我的学生。95%的学生会说。显然按钮0显示0,按钮1显示1,等等。而不足5%的学生学习了闭包之后会明白。所有的按钮都会显示10. 局部变量i的值改变了。并且等于buttons.Length。也就是10了。想要避免这个诡异的情况也很简单。如下就行了。 问题解决了,但是index变量是一个值类型,因此保留了“全局”i的一个拷贝 最后一个话题是一个叫做表达式树的东西,他和Lambda表达式协作。并且,他会使得在ASP.NET MVC中的Html扩展方法发生一些很奇妙的东西。关键的问题是:如何发现目标函数 1. 传递进去的变量的名称是什么 2. 方法的主体是什么 3. 函数体里使用了什么类型 Expression 解决了这些问题,他允许我们挖掘生成的表达式树,我们也可以执行传递给Func和Action委托的函数,而且,可以在运行时解析Lambda表达式 我们看一下如何使用Expression 类型的例子 这是Expression最简单的用法了。规则也相当直接。通过构建一个Expression类型的对象。编译器为生成的解释树生成一些元数据。这个解释树包含所有相关的信息,比如参数和方法体。 方法体包含完整的解释树,我们可以访问这些操作。就像完整的语句一样。也可以操作返回指和类型。当然,返回可以为null,无论如此。大多数情况下。我们对表达式很感兴趣。这和ASP.NET MVC中处理Expression类型的方法是很相似的—可以得到使用的参数的名字,而好处是显而易见的。不会出现名称拼写错误了。也就不会出现因此而出现的编译错误了。 注意:当程序员仅仅对调用的属性的名字感兴趣的时候。有一个更简单,更优雅的解决方案,那就是参数特性CallerMemberName 这个特性可以得到调用方法/属性的名称。而字段被编译器自动填充。因此,如果我们仅仅想知道名字,而不想知道其他更多的信息,那么我我们只需要写出像下面这个例子里的代码就行了。通过调用WhatsMyName() 方法可以返回方法的名字 Lambda表达式的性能 有一个很大的问题:Lambda表达式有多快?好吧。首先,我们期望他们能和我们一般的函数一样快。下一节里。我们会看到Lambda的MSIL代码和普通的函数没有太大的不同。 最有趣的一个讨论是如果Lambda表达式产生了闭包,将会和使用全局变量的方法一样快。这就产生了一个有趣的问题,和一个区域内局部变量的数目多少会有关系吗? 我们看看测试代码,通过4个不同的指标,我们可以看到普通方法和Lambda方法的不同。 本来用Lambda表达式我们可以把代码写的更好。最终我没有这样做。是为了防止影响看最后的结果。因此,本质上。上述代码里有三个方法 1个是Lambda测试,一个是普通测试,还有一个是在普通测试里调用的方法。而没有的第四个方法其实是我们的lambda表达式。在第一个方法里已经创建了。计算过程很简单,我们随机取数字防止编译器做任何优化。最后我们对普通方法和Lambda方法的不同很有兴趣。 如果我们运行这个测试程序。我们会发现Lambda表达式并不总是比普通方法差。我们惊奇的是有时候甚至Lambda表达式更快一些。然而,在有闭包的情况下,,就不对了。这就是说大多数情况下我们可以毫不犹豫的使用lambda表达式。当使用闭包的时候会出现一点点的性能损失,不过还好,下一节会讲述性能损失的几个原因。 下面是测试输出的结果表 Test Lambda [ms] Normal [ms] 0 45+-1 46+-1 1 44+-1 46+-2 2 49+-3 45+-2 3 48+-2 45+-2 下图是上表的结果,我们可以看得到普通的方法和Lambda表达式基本上限差不多。当使用Lambda表达式的时候没有太大的性能损失。 第三部分会介绍背后的秘密-MSIL