<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_海鸥航迹</title><subtitle type="text">学习之笔记，好文之收集。</subtitle><id>http://feed.cnblogs.com/blog/u/5077/rss</id><updated>2011-08-19T15:08:28Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/5077/rss"/><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/08/19/2146354.html</id><title type="text">Windows批处理中的等待技巧</title><summary type="text">1、直接使用Windows 2003资源工具包中的Sleep.exe 程序，它在全系列Windows中都可以运行； 2、使用下面的技巧 @ping 127.0.0.1 –n 12 &gt;nul 由于Windows Ping目标地址是间隔1秒，上面的指令相当于等候12秒；</summary><published>2011-08-19T15:08:00Z</published><updated>2011-08-19T15:08:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/08/19/2146354.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/08/19/2146354.html"/><content type="html">&lt;p&gt;1、直接使用Windows 2003资源工具包中的Sleep.exe 程序，它在全系列Windows中都可以运行；&lt;/p&gt; &lt;p&gt;2、使用下面的技巧&lt;/p&gt; &lt;p&gt;@ping 127.0.0.1 –n 12 &amp;gt;nul&lt;/p&gt; &lt;p&gt;由于Windows Ping目标地址是间隔1秒，上面的指令相当于等候12秒；&lt;/p&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2146354.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/08/19/2146354.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133081.html</id><title type="text">The Ice::Current Object</title><summary type="text">The Ice::Current Object 服务器端Servant骨架方法（skeleton operation）都有一个Ice::Current类型的参数，这个对象定义如下: module Ice { local dictionary&lt;string, string&gt; Context; enum OperationMode { Normal, \Nonmutating, \Idempotent...</summary><published>2011-08-09T14:46:00Z</published><updated>2011-08-09T14:46:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133081.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133081.html"/><content type="html">&lt;p&gt;The Ice::Current Object &lt;p&gt;服务器端Servant骨架方法（skeleton operation）都有一个Ice::Current类型的参数，这个对象定义如下: &lt;p&gt;module Ice {  &lt;p&gt;local dictionary&amp;lt;string, string&amp;gt; Context;  &lt;p&gt;enum OperationMode { Normal, \Nonmutating, \Idempotent };  &lt;p&gt;local struct Current {  &lt;p&gt;ObjectAdapter adapter;  &lt;p&gt;Connection con;  &lt;p&gt;Identity id;  &lt;p&gt;string facet;  &lt;p&gt;string operation;  &lt;p&gt;OperationMode mode;  &lt;p&gt;Context ctx;  &lt;p&gt;int requestId;  &lt;p&gt;};  &lt;p&gt;}; &lt;p&gt;这个对象提供了服务器端实现当前正在执行的这个操作的一些信息访问入口： &lt;p&gt;adapter： &lt;p&gt;adapter成员提供对object adapter的访问，请求就是通过它被分派的。依次的，adapter提供对communicator的访问，通过getCommunicator操作，如此，就能访问到ICE一切环境信息，如配置属性。 &lt;p&gt;con &lt;p&gt;con成员提供对接收请求的连接的访问，参见37.5.1； &lt;p&gt;id &lt;p&gt;id成员提供当前请求的对象标识，实际就是当前servant的对象标识。 &lt;p&gt;Facet &lt;p&gt;提供对当前请求的facet的访问； &lt;p&gt;Operation &lt;p&gt;包含了要调用的方法的名称。注意操作名也可能是Ice::Object 上的方法，诸如ice_ping,ice_isA（checkCast方法会调用ice_isA）等等； &lt;p&gt;Mode &lt;p&gt;代表当前操作的调用模式； &lt;p&gt;Ctx &lt;p&gt;包含了当前调用的上下文； &lt;p&gt;RequestId &lt;p&gt;Ice协议的请求ID；&lt;/p&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2133081.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133081.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133080.html</id><title type="text">ICE代理的固有方法</title><summary type="text">Table 32.1. The semantics of core proxy methods. Method Description Remote ice_isA Returns true if the remote object supports the type indi­cated by the id argument, oth­erwise false. This method can...</summary><published>2011-08-09T14:45:00Z</published><updated>2011-08-09T14:45:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133080.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133080.html"/><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="0"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="700"&gt; &lt;p&gt;&lt;b&gt;Table 32.1. The semantics of core proxy methods.&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;Method&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Description&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Remote&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isA&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the remote object supports the type indi&amp;shy;cated by the id argument, oth&amp;shy;erwise false. This method can only be invoked on a two&amp;shy;way proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Yes&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_ping&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Determines whether the remote object is reachable. Does not return a value.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Yes&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_ids&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the type ids of the types supported by the remote object. The return value is an array of strings. This method can only be invoked on a twoway proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Yes&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_id&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the type id of the most-derived type supported by the remote object. This method can only be invoked on a twoway proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Yes&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getHash&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a hash value for the proxy for C++. For other lan&amp;shy;guage mappings, use the built-in hash method.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getCommunicator&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the communicator that was used to create this proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_toString&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the string representa&amp;shy;tion of the proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_identity&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy having the given identity.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getIdentity&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the identity of the Ice object represented by the proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_adapterId&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy having the given adapter id.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getAdapterId&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the proxy’s adapter id, or an empty string if no adapter id is configured.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_endpoints&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy having the given endpoints.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getEndpoints&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Connections.37.5.html#73461"&gt;Returns a sequence of End&amp;shy;point objects representing the proxy’s endpoints. See Section 36.5.2 for more infor&amp;shy;mation.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_endpointSelection&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Connections.37.3.html#76915"&gt;Returns a new proxy having the given selection policy (random or ordered). See Section 36.3.1 for more information.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getEndpointSelection&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the endpoint selection policy for the proxy.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_context&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.12.html#122720"&gt;Returns a new proxy having the given request context. See Section 32.12 for more infor&amp;shy;mation on request contexts.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getContext&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.12.html#122720"&gt;Returns the request context associated with the proxy. See Section 32.12 for more infor&amp;shy;mation on request contexts.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_facet&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Facets.html#21951"&gt;Returns a new proxy having the given facet name. See Chapter 33 for more informa&amp;shy;tion on facets.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getFacet&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Facets.html#21951"&gt;Returns the name of the facet associated with the proxy, or an empty string if no facet has been set. See Chapter 33 for more information on facets.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_twoway&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy for mak&amp;shy;ing twoway invocations.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isTwoway&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses twoway invocations, otherwise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_oneway&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.14.html#122892"&gt;Returns a new proxy for mak&amp;shy;ing oneway invocations (see Section 32.14).&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isOneway&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses oneway invocations, otherwise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_batchOneway&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.16.html#123005"&gt;Returns a new proxy for mak&amp;shy;ing batch oneway invocations (see Section 32.16).&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isBatchOneway&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses batch oneway invocations, oth&amp;shy;erwise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_datagram&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.15.html#122976"&gt;Returns a new proxy for mak&amp;shy;ing datagram invocations (see Section 32.15).&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isDatagram&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses datagram invocations, other&amp;shy;wise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_batchDatagram&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.16.html#123005"&gt;Returns a new proxy for mak&amp;shy;ing batch datagram invocations (see Section 32.16).&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isBatchDatagram&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses batch datagram invocations, otherwise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_secure&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy whose endpoints may be filtered depending on the boolean argu&amp;shy;ment. If true, only endpoints using secure transports are allowed, otherwise all end&amp;shy;points are allowed.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isSecure&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses only secure endpoints, other&amp;shy;wise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_preferSecure&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy whose endpoints are filtered depend&amp;shy;ing on the boolean argument. If true, endpoints using secure transports are given precedence over endpoints using non-secure transports. If false, the default behavior gives prece&amp;shy;dence to endpoints using non-secure transports.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isPreferSecure&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy pre&amp;shy;fers secure endpoints, otherwise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_compress&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy whose protocol compression capability is determined by the boolean argument. If true, the proxy uses protocol compression if it is supported by the endpoint. If false, protocol compression is never used.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_timeout&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.13.html#122858"&gt;Returns a new proxy with the given timeout value in millisec&amp;shy;onds. A value of ‑1 disables timeouts. See Section 32.13 for more information on timeouts.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_router&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Glacier2.html#68464"&gt;Returns a new proxy configured with the given router proxy. See Chapter 42 for more informa&amp;shy;tion on routers.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getRouter&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the router that is con&amp;shy;figured for the proxy (null if no router is configured).&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_locator&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/IceGrid.html#22064"&gt;Returns a new proxy with the specified locator. See Chapter 38 for more informa&amp;shy;tion on locators.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getLocator&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the locator that is con&amp;shy;figured for the proxy (null if no locator is configured).&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_locatorCacheTimeout&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy with the specified locator cache time&amp;shy;out. When binding a proxy to an endpoint, the run time caches the proxy returned by the loca&amp;shy;tor and uses the cached proxy while the cached proxy has been in the cache for less than the timeout. Proxies older than the timeout cause the run time to rebind via the locator. A value of 0 disables caching entirely, and a value of ‑1 means that cached proxies never expire. The default value is ‑1.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getLocatorCacheTimeout&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the locator cache time&amp;shy;out value in seconds.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_collocationOptimized&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns a new proxy configured for collocation optimization. If true, collocated optimiza&amp;shy;tions are enabled. The default value is true.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isCollocationOptimized&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses collocation optimization, other&amp;shy;wise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_connectionId&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Connections.37.3.html#75140"&gt;Returns a new proxy having the given connection identifier. See Section 36.3.3 for more infor&amp;shy;mation.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getConnectionId&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns the connection id, or an empty string if no connection id has been configured.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getConnection&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Connections.37.5.html#71945"&gt;Returns an object representing the connection used by the proxy. If the proxy is not cur&amp;shy;rently associated with a connec&amp;shy;tion, the Ice run time attempts to establish a connection first. See Section 36.5 for more information.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_getCachedConnection&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Connections.37.5.html#71945"&gt;Returns an object representing the connection used by the proxy, or null if the proxy is not currently associated with a con&amp;shy;nection. See Section 36.5 for more information.&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_connectionCached&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Connections.37.3.html#76776"&gt;Enables or disables connection caching for the proxy. See Section 36.3.4 for more infor&amp;shy;mation&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_isConnectionCached&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Returns true if the proxy uses connection caching, otherwise false.&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;No&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_flushBatchRequests&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;&lt;u&gt;&lt;a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Adv_server.33.16.html#123005"&gt;Sends a batch of operation invocations synchronously or asynchronously (see Section 32.16).&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Yes&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;begin_ice_flushBatchRequests&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;ice_invoke&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt; &lt;p&gt;Allows dynamic invocation of an operation without the need for compiled Slice definitions. Requests can be sent synchro&amp;shy;nously (see Section 35.3.1) or asynchronously (see Section 35.4).&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt; &lt;p&gt;Yes&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt; &lt;p&gt;&lt;b&gt;begin_ice_invoke&lt;/b&gt;&lt;/p&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="248"&gt;&lt;/td&gt; &lt;td valign="top" width="388"&gt;&lt;/td&gt; &lt;td valign="top" width="63"&gt;&lt;/td&gt; &lt;td valign="top" width="72"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2133080.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/08/09/2133080.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/08/07/2130284.html</id><title type="text">C# Tips 2则</title><summary type="text">C# Textbox Auto Scroll To End ScrollToCaret Scrolling TextboxMany of my sample C# codes,I use textbox to write the results. When textbox is multiline property set to true, and when I insert text into ...</summary><published>2011-08-07T13:42:00Z</published><updated>2011-08-07T13:42:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/08/07/2130284.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/08/07/2130284.html"/><content type="html">&lt;p&gt;&lt;strong&gt;C# Textbox Auto Scroll To End ScrollToCaret Scrolling Textbox&lt;/strong&gt;&lt;br&gt;Many of my sample C# codes,&lt;br&gt;I use textbox to write the results.&lt;/p&gt; &lt;p&gt;When textbox is multiline property set to true, and when I insert text into it,&lt;br&gt;I want it to auto scroll to the last line.&lt;/p&gt; &lt;p&gt;Here is a simple way to auto scrolling textbox.&lt;/p&gt; &lt;p&gt; textbox1.SelectionStart = textbox1.Text.Length;&lt;br&gt; textbox1.ScrollToCaret();&lt;br&gt; textbox1.Refresh();&lt;/p&gt; &lt;p&gt;Textbox SelectionStart will force the textbox control to select the last part of the text,&lt;br&gt;and ScrollToCaret() function will auto scroll textbox to the end. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;font style="font-weight: bold"&gt;C# Convert Hexadecimal to Binary String Conversion &lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;There is no need to code tons of codes, loops, to convert&lt;strong&gt; hex to binary string&lt;/strong&gt;. &lt;strong&gt;Convert.ToInt32&lt;/strong&gt; function is very useful for this purpose.&lt;br&gt;Let's convert the "A" character to binary format. private string hex2binary(string hexvalue)&lt;br&gt;{&lt;br&gt;  string binaryval = "";&lt;br&gt;  binaryval = Convert.ToString(Convert.ToInt32(hexvalue, 16), 2);&lt;br&gt;  return binaryval;&lt;br&gt;}When we call &lt;strong&gt;hex2binary&lt;/strong&gt;("A"); it will return "1010" similar samples below;&lt;br&gt;&lt;strong&gt;hex2binary&lt;/strong&gt;("&lt;strong&gt;1a&lt;/strong&gt;"); will return "&lt;strong&gt;11010&lt;/strong&gt;";&lt;br&gt;&lt;strong&gt;hex2bianry&lt;/strong&gt;("&lt;strong&gt;1a2c&lt;/strong&gt;"); will return "&lt;strong&gt;1101000101100&lt;/strong&gt;"; and so on.&lt;br&gt;Keep in mind that this &lt;strong&gt;hex to binary conversion&lt;/strong&gt; style uses &lt;strong&gt;32 bit integer&lt;/strong&gt; number. &lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2130284.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/08/07/2130284.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/08/02/2125508.html</id><title type="text">Configuring log4net with VS2010 and .Net 4.0</title><summary type="text">Configuring log4net with VS2010 and .Net 4.0 After spending a few hours this morning trying to get l...</summary><published>2011-08-02T13:28:00Z</published><updated>2011-08-02T13:28:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/08/02/2125508.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/08/02/2125508.html"/><content type="html">&lt;p&gt;&lt;strong&gt;Configuring log4net with VS2010 and .Net 4.0&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;After spending a few hours this morning trying to get log4net working with a project, I decided to share my findings.&amp;nbsp;&amp;nbsp; I chased a lot of dead-ends for what wound up being a fairly simple solution.&amp;nbsp; Here is a quick article to save both myself, and maybe you, some time in the future.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Get Log4Net&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Go to &lt;a href="http://logging.apache.org/log4net/"&gt;http://logging.apache.org/log4net/&lt;/a&gt; and get the latest version.&amp;nbsp;&amp;nbsp;&amp;nbsp; Add the project file to your solution.&amp;nbsp;&amp;nbsp; Then right-click that project, choose the build tab and…&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;strong&gt;Step 1: Set the log4net conditional compilation symbols replacing NET_1_0 with NET_4_0.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;Log4Net Requires Full .Net Access&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;That means you cannot use “client profile”.&amp;nbsp; log4net was originally written to log web services.&amp;nbsp; As such it expects to have a lot of server-side classes available, even though most of those classes are never instantiated.&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;&lt;strong&gt;: Build&amp;nbsp; Your Application &amp;amp; The Log4Net component under .Net 4.0, not .Net 4.0 Client Profile&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;Make Log4Net Less Secure&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The .Net 4.0 assemblies are more secure by default.&amp;nbsp; You need to override this.&amp;nbsp;&amp;nbsp; As I’m not a .Net development guru I’m not really certain what the differences mean, but Google is your friend (and mine) here, so if you are concerned (and you should be before launching a public app) then search the Internet to find out what this mean. In the meantime…&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;strong&gt;Step 3: Make log4net assembly less secure, add &lt;/strong&gt;&lt;br&gt;&lt;strong&gt;&lt;code&gt;[assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)]&lt;/code&gt;&lt;/strong&gt; &lt;br&gt;&lt;strong&gt;to the log4net AssemblyInfo.cs file.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;Done.&lt;strong&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;That’s it, the first steps for getting a log4net component into your application.&amp;nbsp;&amp;nbsp; Now you can follow some of the development &amp;amp; deployment document on the Apache site:&lt;/p&gt; &lt;p&gt;&lt;a href="http://logging.apache.org/log4net/release/manual/configuration.html"&gt;http://logging.apache.org/log4net/release/manual/configuration.html&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;编译好的for .net 4.0 的log4net库文件下载：&lt;/p&gt; &lt;p&gt;&lt;a href="http://files.cnblogs.com/sgsoft/log4Net_4.0.zip" target="_blank"&gt;log4net for .net 4.0&lt;/a&gt;&amp;nbsp;&amp;nbsp; : &lt;a title="http://files.cnblogs.com/sgsoft/log4Net_4.0.zip" href="http://files.cnblogs.com/sgsoft/log4Net_4.0.zip"&gt;http://files.cnblogs.com/sgsoft/log4Net_4.0.zip&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2125508.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/08/02/2125508.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119967.html</id><title type="text">IoC Container Benchmark - Unity, Windsor, StructureMap and Spring.NET</title><summary type="text">There are a number of inversion of control containers out there so I thought it would be an interesting experiment to do a simple benchmark. There are different ways that one can instantiate a type in...</summary><published>2011-07-28T13:23:00Z</published><updated>2011-07-28T13:23:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119967.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119967.html"/><content type="html">&lt;p&gt;There are a number of inversion of control containers out there so I thought it would be an interesting experiment to do a simple benchmark. There are different ways that one can instantiate a type in .NET, for example via the new operator, Activator, GetUninitializedObject and Dynamic Method. The performance difference between these methods are in some cases quite high, maybe the same is true for these IoC containers? Granted IoC containers do more than just create objects so other factors will probably play a big role in the results.&lt;/p&gt; &lt;p&gt;So here are the contestants:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Castle Windsor  &lt;ul&gt; &lt;li&gt;Part of the popular &lt;a href="http://www.castleproject.com"&gt;Castle Project&lt;/a&gt;.  &lt;li&gt;First &lt;a href="http://www.codeproject.com/KB/architecture/introducingcastle.aspx"&gt;introduced&lt;/a&gt; in 2004 &lt;/li&gt;&lt;/ul&gt; &lt;li&gt;StructureMap  &lt;ul&gt; &lt;li&gt;&lt;a href="http://structuremap.sourceforge.net/"&gt;Sourceforge&lt;/a&gt; project maintained and created by &lt;a href="http://codebetter.com/blogs/jeremy.miller/default.aspx"&gt;Jeremy D. Miller&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Spring.NET  &lt;ul&gt; &lt;li&gt;Inspired by the spring java framework  &lt;li&gt;First introduced in 2004, &lt;a href="http://www.springframework.net"&gt;www.springframework.net&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Unity  &lt;ul&gt; &lt;li&gt;Created by the Microsoft Patterns Practices team  &lt;li&gt;First released in April 2008  &lt;li&gt;Project homepage on &lt;a href="http://www.codeplex.com/unity"&gt;codeplex&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;I have been using Castle Windsor since 2005 and I think it is the best of the bunch, so I guess I am unconsciously biased toward Windsor.&amp;nbsp; However I will try to make this benchmark as objective as I can. &lt;/p&gt; &lt;p&gt;The scenario for this test:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Have each IoC container resolve a UserController 1000 000 times  &lt;li&gt;The UserController will have two constructor dependencies  &lt;li&gt;Run the test with transient (new instance for each resolve) and singleton components &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The UserController looks like this:&lt;/p&gt; &lt;p&gt;public class UserController&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;private IUserRepository repository;&lt;/p&gt; &lt;p&gt;private IAuthentificationService authService;&lt;/p&gt; &lt;p&gt;public UserController(IUserRepository repository, IAuthentificationService authService)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;this.repository = repository;&lt;/p&gt; &lt;p&gt;this.authService = authService;&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;I have also a general container interface that the benchmark engine will use. Each container will implement this interface. &lt;/p&gt; &lt;p&gt;public interface IContainer&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;string Name { get; }&lt;/p&gt; &lt;p&gt;T Resolve&amp;lt;T&amp;gt;();&lt;/p&gt; &lt;p&gt;void SetupForTransientTest();&lt;/p&gt; &lt;p&gt;void SetupForSingletonTest();&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;All tests used the latest released version of each library. Before you interpret these charts please observe that the measurement is for one million component resolves which means the actual time difference between each container is actually very small. &lt;/p&gt; &lt;p&gt;Here are the results when all components were setup as singletons: &lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/torkel.odegaard/SALhluJA3tI/AAAAAAAAAV4/s_D-8NyaA68/s1600-h/IoCSingleton4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122354512.gif" width="244" height="147"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Here are the results when all components were setup as transient:&lt;/p&gt; &lt;p&gt;&lt;a href="http://lh5.ggpht.com/torkel.odegaard/SALhmuJA3vI/AAAAAAAAAWI/ggWWz0q0y4Y/s1600-h/IoCTransient4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122369953.gif" width="244" height="143"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;So what does these charts tell us? Lets take the biggest difference in the transient case, Spring.NET took 44.149 seconds and Unity took 8.164 seconds, what is the actual difference when resolving a single instance?&lt;/p&gt; &lt;p&gt;Spring.NET : 44.149 / 1000000 = 0.000044149 seconds&lt;/p&gt; &lt;p&gt;Unity : 8.164 / 1000000 = 0.000008164 seconds&lt;/p&gt; &lt;p&gt;So the actual difference is only about 36 microseconds. Another way to put these values into perspective is to compare against the new operator. I created a NewOperatorContainer with a resolve method that looks like this: &lt;/p&gt; &lt;p&gt;public T Resolve&amp;lt;T&amp;gt;()&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;object o = new UserController(new LdapUserRepository(), new DefaultAuthentificationService());&lt;/p&gt; &lt;p&gt;return (T) o;&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;OK, comparing the above with an inversion of control container is like comparing apples to oranges, an IoC handles so much more than just object creation. Also an IoC cannot use the new operator directly but must use one of the other methods. My guess is that all IoC containers in this test uses an approach which involve IL Generation which if cashed comes close to using the new operator directly. Anyway I think it will show just how small the difference between the real IoC containers are. In order to visualize this I needed to invert the values so that high means fast and low means slow. &lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122387770.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122428769.png" width="244" height="147"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a title="http://lh3.ggpht.com/torkel.odegaard/SALo6OJA3yI/AAAAAAAAAWg/Nhrvuby1VUE/s1600-h/IoCInversed[5].png" href="http://lh3.ggpht.com/torkel.odegaard/SALo6OJA3yI/AAAAAAAAAWg/Nhrvuby1VUE/s1600-h/IoCInversed[5].png"&gt;http://lh3.ggpht.com/torkel.odegaard/SALo6OJA3yI/AAAAAAAAAWg/Nhrvuby1VUE/s1600-h/IoCInversed[5].png&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Update: The above chart can be very misleading. The x-axis is not seconds but 1/s. I hope it shows that the difference between the containers are very small compared to instantiating the objects manually.&lt;/p&gt; &lt;p&gt;OK, can we draw any conclusion from the test? Well I think we can say that performance should not be an issue when choosing one of these IoC containers. The difference is too small. When you choose which container to use you should consider other aspects, like how invasive the container is to they way you want to work.&lt;/p&gt; &lt;p&gt;For the complete code: &lt;a href="http://www.codinginstinct.com-a.googlepages.com/IoCBenchmark.zip"&gt;IoCBenchmark.zip&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Posted by Torkel Ödegaard at &lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html"&gt;6:46 AM&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Labels: &lt;a href="http://www.codinginstinct.com/search/label/Benchmarks"&gt;Benchmarks&lt;/a&gt;, &lt;a href="http://www.codinginstinct.com/search/label/C%23"&gt;C#&lt;/a&gt;, &lt;a href="http://www.codinginstinct.com/search/label/Castle"&gt;Castle&lt;/a&gt;, &lt;a href="http://www.codinginstinct.com/search/label/IoC"&gt;IoC&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="comments"&gt;&lt;/a&gt;&lt;b&gt;13 comments: &lt;/b&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c7863896243701007491"&gt;&lt;/a&gt;Anonymous said... &lt;/p&gt; &lt;p&gt;IMHO your last graph is very misleading. why do you use the inverse values? use the usual values and point out how tiny the "new" value is - or if you feel like the inverse is beneficial at least label your axis correctly. &lt;br&gt;otherwise nice article&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208172000000#c7863896243701007491"&gt;April 14, 2008 1:20 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=7863896243701007491"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006" border="0" alt="clip_image006" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122428703.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c5341051240608847896"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/08914354140151859277"&gt;Torkel Ödegaard&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;Yes, you are right. I also feel that the last graph is too misleading. I will correct it when I get home from work.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208172300000#c5341051240608847896"&gt;April 14, 2008 1:25 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=5341051240608847896"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[1]" border="0" alt="clip_image006[1]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122433621.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c8579671090295741135"&gt;&lt;/a&gt;Joshua said... &lt;/p&gt; &lt;p&gt;I would interested to see how Ninject compares.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208192220000#c8579671090295741135"&gt;April 14, 2008 6:57 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=8579671090295741135"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[2]" border="0" alt="clip_image006[2]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122444635.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c7418820709950430922"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/08914354140151859277"&gt;Torkel Ödegaard&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;I guess it should have been in the test having a slogan like "Lightning-fast dependency injection for .NET" &lt;br&gt;Hopefully I will have time to do it later in the week, thanks for the tip!&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208194800000#c7418820709950430922"&gt;April 14, 2008 7:40 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=7418820709950430922"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[3]" border="0" alt="clip_image006[3]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122457883.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c5483004876407316911"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/07590604974965398443"&gt;Bil Simser&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;This is interesting but IMHO a bit of a waste of time. I mean, what application would *ever* need to try to create a million objects all at once? Even in a tight loop you *might* create a few thousand objects. I just can't think of any use case where this situation would ever manifest itself so to me the numbers are pretty meaningless. Interesting to look at, but not of any value to judge something by. If the differences were significant with say a few hundred objects then maybe this exercise would be worth something.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208353980000#c5483004876407316911"&gt;April 16, 2008 3:53 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=5483004876407316911"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[4]" border="0" alt="clip_image006[4]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122466945.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c448846080907593363"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/08914354140151859277"&gt;Torkel Ödegaard&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;Yes, I agree that this is not a realistic scenario. Doing one million resolves is not something that do in one request. That was just to accumulate the performance difference to see if there were any substantial difference. &lt;br&gt;I don't think it was a waste of time, because it could have potentially been a big meaningful difference between them. Now it turned out that there weren't but that didn't make the test meaningless, because now you know :)&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208355900000#c448846080907593363"&gt;April 16, 2008 4:25 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=448846080907593363"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[5]" border="0" alt="clip_image006[5]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122493517.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c7734057600921695868"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/12052323511010110369"&gt;Nate Kohari&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;Nice post. I'd also be interested to know how Ninject does in comparison. :) &lt;br&gt;Bil's right, though, that it wouldn't typically make a difference, because most applications don't need to create 1,000,000 instances. However, faster IoC also means that you can use it in places that you wouldn't otherwise be able to -- for example, devices that support the compact framework. &lt;br&gt;Still a worthwhile study, and it's interesting to see the results!&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208374980000#c7734057600921695868"&gt;April 16, 2008 9:43 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=7734057600921695868"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[6]" border="0" alt="clip_image006[6]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122518368.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c6381607770819368452"&gt;&lt;/a&gt;&lt;a href="http://www.sitechno.com/blog"&gt;Ruurd Boeke&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;I'm sorry, but if you are going to do a test and find a huge relative difference, you should not disregard it by looking at the absolute difference. What's the point in doing the test than? &lt;br&gt;I think it's pretty clear that no container takes a very long time, so what were you hoping to find? &lt;br&gt;(no disrespect meant, I clicked on the post because I was curious as well ;-) )&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208376540000#c6381607770819368452"&gt;April 16, 2008 10:09 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=6381607770819368452"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[7]" border="0" alt="clip_image006[7]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122518302.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c865442479124522262"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/08914354140151859277"&gt;Torkel Ödegaard&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;Well the point was to check if there was any relevant difference, not to check which was the fastest. &lt;br&gt;And I think you can actually disregard a relative difference if that difference is still not relevant when you look at the absolute performance. &lt;br&gt;My conclusion to the test was that the relative difference was too small to make any relevant difference in real applications.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208378460000#c865442479124522262"&gt;April 16, 2008 10:41 PM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=865442479124522262"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[8]" border="0" alt="clip_image006[8]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122524648.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c645688987547225159"&gt;&lt;/a&gt;Anonymous said... &lt;/p&gt; &lt;p&gt;Nice benchmark. A functional comparison for the used Ioc Containers would be interesting. Where do the performance differences come from?&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208416800000#c645688987547225159"&gt;April 17, 2008 9:20 AM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=645688987547225159"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[9]" border="0" alt="clip_image006[9]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122526218.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c218336915987423264"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/02020072230899910249"&gt;Nick&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;I think the comment about functional differences is important - what are you getting for you time? &lt;br&gt;In a real app with more components, the factors affecting container performance will shift from the expense of creating instances, to the expense associated with algorithms that are affected by the number of instances (e.g. which instance from many should be returned?) and algorithms that take a time proportional to the size of the dependency graph (e.g. circular dependency checking.) &lt;br&gt;You can never tell where that performance bottleneck is going to be until you measure it ;)&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1208671740000#c218336915987423264"&gt;April 20, 2008 8:09 AM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=218336915987423264"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[10]" border="0" alt="clip_image006[10]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122533088.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c2397203543160065036"&gt;&lt;/a&gt;&lt;a href="http://myonlineband.com"&gt;sharkboy&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;I think what this page shows is that using IOC containers will not make your app significantly slower. What makes apps slow are poor design, bad databases, and network latency. &lt;br&gt;As to which one to use, you have to try and figure out which one has a future. &lt;br&gt;I would rule out Spring.Net because it is a Java port and will always be several steps behind in supporting the latest .Net framework features. &lt;br&gt;StructureMap is cool but since only one guy is supporting it I would expect the project to die once that dude gets tired of dealing with it. &lt;br&gt;Unity may be the safe bet being that it has "Official" support from Microsoft. The MS guys where starting to promote this at TechEd this year. On the other hand, don't expect any innovation from Microsoft. &lt;br&gt;If you want a supported component, go with Unity. If you want innovation, go Windsor.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1213590240000#c2397203543160065036"&gt;June 16, 2008 6:24 AM &lt;/a&gt;&lt;a href="http://www.blogger.com/delete-comment.g?blogID=3198935374994345981&amp;amp;postID=2397203543160065036"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image006[11]" border="0" alt="clip_image006[11]" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107282122546053.gif" width="32" height="32"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a name="c5081591882937675838"&gt;&lt;/a&gt;&lt;a href="http://www.blogger.com/profile/08895029945395731837"&gt;Luke&lt;/a&gt; said... &lt;/p&gt; &lt;p&gt;You clearly don't know Jeremy Miller very well if you think that's what'll happen with StructureMap.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html?showComment=1215358260000#c5081591882937675838"&gt;July 6, 2008 5:31 PM &lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2119967.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119967.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119965.html</id><title type="text">Functional .NET 4.0 &amp;ndash; Tuples and Zip</title><summary type="text">Previously, when covering some of the additions to the .NET 4.0 Framework such as optional and named parameters, some of the other additions have caught my eye from the perspective of functional progr...</summary><published>2011-07-28T13:21:00Z</published><updated>2011-07-28T13:21:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119965.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119965.html"/><content type="html">&lt;p&gt;Previously, when covering some of the additions to the .NET 4.0 Framework such as &lt;a href="http://codebetter.com/blogs/matthew.podwysocki/archive/2008/10/29/c-4-0-named-and-optional-parameters-behind-the-scenes.aspx"&gt;optional and named parameters&lt;/a&gt;, some of the other additions have caught my eye from the perspective of functional programming.&amp;nbsp; Unlike .NET 3.5, this release is not as targeted towards functional programming as it is more towards dynamic programming and COM interoperability.&amp;nbsp; But, there are a few items to note that we can soon take advantage of, including the Tuple type and the Zip operator function among other items.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Looking at Tuples&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;To define a tuple, it comes from the mathematics field, and is simply an ordered list of values, which are components of that tuple.&amp;nbsp; These components can be of any type, whether it be string, integer, or otherwise.&amp;nbsp; In order to refer to these components, we retrieve references to them by absolute position in that sequence.&lt;/p&gt; &lt;p&gt;In F#, the tuple is a fully supported data type and perhaps one of the most useful.&amp;nbsp; To define a tuple is to define a number of expressions grouped together with comma separation to form a new expression such as the following:&lt;/p&gt; &lt;p&gt;#light&lt;/p&gt; &lt;p&gt;// val blogger : string * string &lt;br&gt;let blogger1 = "Matthew", "Podwysocki" &lt;br&gt;let blogger2 = "Jeremy", "Miller" &lt;br&gt;let blogger3 = "David", "Laribee"&lt;/p&gt; &lt;p&gt;// val bloggers : &lt;br&gt;// (string * string) * (string * string) * (string * string) &lt;br&gt;let bloggers = blogger1, blogger2, blogger3&lt;/p&gt; &lt;p&gt;From there, tuples can be decomposed into their components in either of two ways.&amp;nbsp; For pair tuples, a tuple with exactly two components, can be deconstructed using the fst and snd functions such as the following:&lt;/p&gt; &lt;p&gt;#light&lt;/p&gt; &lt;p&gt;let pageHitCount = "http://www.codebetter.com/", 25500 &lt;br&gt;let page = fst pageHitCount &lt;br&gt;let hitCount = snd pageHitCount&lt;/p&gt; &lt;p&gt;However, it is more common to use a pattern expression to retrieve values from a tuple, such as the following code:&lt;/p&gt; &lt;p&gt;#light&lt;/p&gt; &lt;p&gt;let request =&amp;nbsp; &lt;br&gt;"http://codebetter",&amp;nbsp; &lt;br&gt;new DateTime(2008, 11, 15), &lt;br&gt;"Firefox/3.0.4 (.NET CLR 3.5.30729)"&lt;/p&gt; &lt;p&gt;let host, date, userAgent = request&lt;/p&gt; &lt;p&gt;What we’re able to do is break down the given request into three pieces, the host, date and user-agent.&amp;nbsp; This makes pattern matching against tuples really powerful such as the following:&lt;/p&gt; &lt;p&gt;#light&lt;/p&gt; &lt;p&gt;// val permit_request : string * string * int -&amp;gt; bool &lt;br&gt;let permit_request = function &lt;br&gt;| "http", "google.com", 80 -&amp;gt; true &lt;br&gt;| _, "microsoft.com", _ -&amp;gt; true &lt;br&gt;| "ftp", _, 21 -&amp;gt; true &lt;br&gt;| _ -&amp;gt; false&lt;/p&gt; &lt;p&gt;Just as well, we could even use them in active patterns so that we could pattern match against parts of a FileVersionInfo in order to determine which action to take such as the following.&lt;/p&gt; &lt;p&gt;#light&lt;/p&gt; &lt;p&gt;open System.Diagnostics &lt;/p&gt; &lt;p&gt;let (|FileVersionSections|) (f:FileVersionInfo) =&amp;nbsp; &lt;br&gt;(f.FileName,f.ProductName,f.ProductVersion) &lt;br&gt;let parse_files = function &lt;br&gt;| FileVersionSections(fn, "Parallel Extensions for the .NET Framework", _) &lt;br&gt;-&amp;gt; printfn "Parallel Extensions file %s" fn &lt;br&gt;| FileVersionSections(fn, "Microsoft Office Communicator 2007", _) &lt;br&gt;-&amp;gt; printfn "Communicator file %s" fn &lt;br&gt;| _ -&amp;gt; printfn "Unknown file"&lt;/p&gt; &lt;p&gt;You’re saying, great, but what has this to do with .NET 4.0?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Tuples in .NET 4.0&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Earlier this month, &lt;a href="http://blogs.msdn.com/bclteam/archive/2008/11/04/what-s-new-in-the-bcl-in-net-4-0-justin-van-patten.aspx"&gt;Justin Van Patten, on the BCL Team Blog&lt;/a&gt; announced some the base class library changes coming to .NET 4.0.&amp;nbsp; Among them was Tuples in which was stated:&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;We are providing common tuple types in the BCL to facilitate language interoperability and to reduce duplication in the framework.&amp;nbsp; A tuple is a simple generic data structure that holds an ordered set of items of heterogeneous types.&amp;nbsp; Tuples are supported natively in languages such as F# and IronPython, but are also easy to use from any .NET language such as C# and VB.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;What does that mean exactly?&amp;nbsp; Does this mean we’ll get some form of syntactic sugar around them as well?&amp;nbsp; If we could decompose them in such a fashion as we do in F#, and to initialize them in an easy fashion without a lot of pomp and circumstance.&amp;nbsp; Gazing from the intent in the .NET libraries, something like this might be an option:&lt;/p&gt; &lt;p&gt;var t1 = Tuple.Create(1, ‘a’);&amp;nbsp; &lt;br&gt;var i1 = t1.Item1;&amp;nbsp; &lt;br&gt;var i2 = t1.Item2;&lt;/p&gt; &lt;p&gt;But, unless there were a nicer way to tease apart the data, it just becomes a simple holder of data, instead of something that we could decompose easily into patterns.&amp;nbsp; I would love to some sort of syntactic sugar in C# to allow for this to happen.&amp;nbsp; I am, however, encouraged that they are working with the F# team and other teams to ensure compatibility between the libraries.&lt;/p&gt; &lt;p&gt;If you open Reflector, you will find the type definitions in mscorlib.dll version 4.0 under the System namespace.&amp;nbsp; You may also be surprised to find them as internal classes only at this point, which is unfortunate and we find ourselves not able to take advantage of these things such as the CodeContracts and BigInteger/BigNumber in the .NET 3.5 libraries.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;As you can see from the above screen catpure, we have up to 7 arguments for a given tuple and the rest as defined by another tuple.&amp;nbsp; I, however, haven’t seen tuples quite that large before, but it’s always possible…&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Zip Operator Function&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Another functional programming item that has been added to the System.Linq.Enumerable class in System.Core.dll.&amp;nbsp; This method allows us to combine two collections together using a function to calculate the new element given the element from each collection.&amp;nbsp; &lt;/p&gt; &lt;p&gt;In F#, we have two ways of doing this in F# in the Seq module.&amp;nbsp; They are defined as:&lt;/p&gt; &lt;p&gt;val map2 : (‘a -&amp;gt; ‘b -&amp;gt; ‘c) -&amp;gt; seq&amp;lt;’a&amp;gt; -&amp;gt; seq&amp;lt;’b&amp;gt; -&amp;gt; seq&amp;lt;’c&amp;gt; &lt;br&gt;val zip : seq&amp;lt;’a&amp;gt; -&amp;gt; seq&amp;lt;’b&amp;gt; -&amp;gt; seq&amp;lt;’a * ‘b&amp;gt;&lt;/p&gt; &lt;p&gt;The map2 function takes a function which takes the two items from the list to produce the calculated item, and two collections and returns a new collection of the computed items.&amp;nbsp; If one collection is shorter than the other, the rest of the computations are not completed.&amp;nbsp; The zip function is a simple function which takes the items from the first and second collection and combines them in a tuple. &lt;/p&gt; &lt;p&gt;An example of each follows:&lt;/p&gt; &lt;p&gt;// Map2 &lt;br&gt;let l1 = seq[1 .. 26] &lt;br&gt;let l2 = seq['a' .. 'z'] &lt;br&gt;let mapped = Seq.map2&amp;nbsp; &lt;br&gt;(fun a b -&amp;gt; sprintf "%d%c" a b) l1 l2 &lt;/p&gt; &lt;p&gt;// Zip &lt;br&gt;let z1 = seq['a' .. 'z'] &lt;br&gt;let z2 = seq['A' .. 'Z'] &lt;br&gt;let zipped = Seq.zip z1 z2&lt;/p&gt; &lt;p&gt;Now, to use the C# version is rather simple.&amp;nbsp; The signature of this method is simply:&lt;/p&gt; &lt;p&gt;public static IEnumerable&amp;lt;TResult&amp;gt; Zip&amp;lt;TFirst, TSecond, TResult&amp;gt;( &lt;br&gt;this IEnumerable&amp;lt;TFirst&amp;gt; first,&amp;nbsp; &lt;br&gt;&amp;nbsp; IEnumerable&amp;lt;TSecond&amp;gt; second,&amp;nbsp; &lt;br&gt;&amp;nbsp; Func&amp;lt;TFirst, TSecond, TResult&amp;gt; func)&lt;/p&gt; &lt;p&gt;As you can see, this follows the same exact pattern as the map2 function from F#, which allows us to compose the two items together via a function to compute the hew item.&amp;nbsp; Let’s define a few tests that will pass given our knowledge of the Zip function.&amp;nbsp; We can also include the Tuple class, well, at least the F# version to show that behavior as well.&amp;nbsp; These are basically tests that I wrote for my Functional C# library, but I hadn’t published my tests, and I probably should.&amp;nbsp; &lt;/p&gt; &lt;p&gt;[Fact] &lt;br&gt;public void ZipWithAdding_ShouldAddRanges() &lt;br&gt;{ &lt;br&gt;// Arrange &lt;br&gt;var range1 = Enumerable.Range(1, 10); &lt;br&gt;var range2 = Enumerable.Range(11, 10); &lt;/p&gt; &lt;p&gt;// Act &lt;br&gt;var range3 = range1.Zip(range2, (i, j) =&amp;gt; i + j); &lt;/p&gt; &lt;p&gt;// Assert &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.Count() == 10); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(0) == 12); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(9) == 30); &lt;br&gt;} &lt;/p&gt; &lt;p&gt;[Fact] &lt;br&gt;public void ZipWithIntAndChar_ShouldCombine() &lt;br&gt;{ &lt;br&gt;// Arrange &lt;br&gt;var range1 = Enumerable.Range(1, 5); &lt;br&gt;var range2 = new[] { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ }; &lt;/p&gt; &lt;p&gt;// Act &lt;br&gt;var range3 = range1.Zip(range2, (i, j) =&amp;gt; i + j.ToString()); &lt;/p&gt; &lt;p&gt;// Assert &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.Count() == 5); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(0) == "1a"); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(4) == "5e"); &lt;br&gt;} &lt;/p&gt; &lt;p&gt;[Fact] &lt;br&gt;public void ZipWithTuples_ShouldCombineLists() &lt;br&gt;{ &lt;br&gt;// Arrange &lt;br&gt;var range1 = Enumerable.Range(1, 5); &lt;br&gt;var range2 = new[] { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ }; &lt;/p&gt; &lt;p&gt;// Act &lt;br&gt;var range3 = range1.Zip(range2, (i, j) =&amp;gt; new Tuple&amp;lt;int, char&amp;gt;(i, j)); &lt;/p&gt; &lt;p&gt;// Assert &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.Count() == 5); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(0).CompareTo( &lt;br&gt;new Tuple&amp;lt;int, char&amp;gt;(1, ‘a’)) == 0); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(4).CompareTo( &lt;br&gt;new Tuple&amp;lt;int, char&amp;gt;(5, ‘e’)) == 0); &lt;br&gt;}&lt;/p&gt; &lt;p&gt;Because the Parallel Extensions for .NET are becoming part of the BCL in .NET 4.0, the ParallelEnumerable also has the Zip method as well, which allows us to take advantage of data parallelism, should our machine allow such as this:&lt;/p&gt; &lt;p&gt;[Fact] &lt;br&gt;public void ParallelZipWithAdding_ShouldAddRanges() &lt;br&gt;{ &lt;br&gt;// Arrange &lt;br&gt;var range1 = ParallelEnumerable.Range(1, 10); &lt;br&gt;var range2 = ParallelEnumerable.Range(11, 10); &lt;/p&gt; &lt;p&gt;// Act &lt;br&gt;var range3 = range1.Zip(range2, (i, j) =&amp;gt; i + j); &lt;/p&gt; &lt;p&gt;// Assert &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.Count() == 10); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(0) == 12); &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.True(range3.ElementAt(9) == 30); &lt;br&gt;}&lt;/p&gt; &lt;p&gt;With the including of the Parallel Extensions for .NET, it’s going to be a lot of more functional fun built-into the BCL.&amp;nbsp; I can only hope for more of this coming down the road.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Wrapping It Up&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Although the .NET Framework 4.0 release didn’t give too many items for functional programming as they had in the .NET 3.5 release, the .NET 4.0 Framework has a few interesting items with the inclusion of the Tuple and Zip method.&amp;nbsp; Even more intrigue of course comes from adding the Parallel Extensions for the .NET Framework to the base class library as a first-class citizen.&amp;nbsp; &lt;/p&gt; &lt;p&gt;I’d wish they would have made the Tuple class public already so that we could at least play around with some of those features, but I as many understand why some of the decisions were made, and I also realize it’s early in the cycle still.&amp;nbsp; Hopefully in the next release or so, it will become available to us to use, including some syntactic sugar about their creation and decomposition, but ultimately, that’s a language decision and not necessarily a framework decision.&amp;nbsp; &lt;/p&gt; &lt;p&gt;It’s great to see a language convergence in terms of libraries now being available to all.&amp;nbsp; F# will continue to be my language of choice, but with C# gaining some of these libraries, it makes the transition switch much easier without having to reinvent the wheel with either re-implementing the feature or converting Func delegates to F# FastFunc types and back again.&lt;/p&gt; &lt;p&gt;This entry was posted in &lt;a href="http://codebetter.com/matthewpodwysocki/category/c/"&gt;C#&lt;/a&gt;, &lt;a href="http://codebetter.com/matthewpodwysocki/category/f/"&gt;F#&lt;/a&gt;, &lt;a href="http://codebetter.com/matthewpodwysocki/category/functional-programming/"&gt;Functional Programming&lt;/a&gt;. Bookmark the &lt;a href="http://codebetter.com/matthewpodwysocki/2008/11/16/functional-net-4-0-tuples-and-zip/"&gt;permalink&lt;/a&gt;. Follow any comments here with the &lt;a href="http://codebetter.com/matthewpodwysocki/2008/11/16/functional-net-4-0-tuples-and-zip/feed/"&gt;RSS feed for this post&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;&lt;a href="http://codebetter.com/matthewpodwysocki/2008/11/14/net-code-contracts-and-tdd-are-complementary/"&gt;← .NET Code Contracts and TDD Are Complementary&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://codebetter.com/matthewpodwysocki/2008/11/18/dc-alt-net-11-25-web-testing-frameworks/"&gt;DC ALT.NET 11/25 – Web Testing Frameworks →&lt;/a&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;p&gt;&lt;cite&gt;rsenna &lt;/cite&gt;&lt;/p&gt; &lt;p&gt;Perhaps I got it wrong.&lt;/p&gt; &lt;p&gt;But your C# *Zip* method represents an implementation of F# *map2* function, right? I’m trying to learn F#, so that got me confused.&lt;/p&gt; &lt;p&gt;Anyway, the zip function may be seen as a special case of map2…&lt;/p&gt; &lt;li&gt; &lt;p&gt;&lt;cite&gt;http://podwysocki.codebetter.com/ Matthew.Podwysocki &lt;/cite&gt;&lt;/p&gt; &lt;p&gt;@rsenna&lt;/p&gt; &lt;p&gt;That is correct, the Zip is an implementation of the map2 function.&lt;/p&gt; &lt;p&gt;Matt&lt;/p&gt; &lt;li&gt; &lt;p&gt;&lt;cite&gt;http://smellegantcode.wordpress.com/ Daniel Earwicker &lt;/cite&gt;&lt;/p&gt; &lt;p&gt;Where you wrote:&lt;/p&gt; &lt;p&gt;var range3 = range1.Zip(range2, (i, j) =&amp;gt; new Tuple(i, j)); &lt;/p&gt; &lt;p&gt;You can actually just put:&lt;/p&gt; &lt;p&gt;var range3 = range1.Zip(range2, Tuple.Create); &lt;/p&gt; &lt;p&gt;This is because there’s a static non-generic helper class with generic overloads of Create (for up to 8 args). Neat!&lt;/p&gt; &lt;li&gt; &lt;p&gt;&lt;cite&gt;http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki &lt;/cite&gt;&lt;/p&gt; &lt;p&gt;@Daniel,&lt;/p&gt; &lt;p&gt;You are correct, but this wasn’t there at the time this post was done.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2119965.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119965.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119964.html</id><title type="text">binary search of an integer array</title><summary type="text">二分法查找 1: // binary search of an integer array, this search is efficient for large arrays 2: // tested with PellesC vegaseat 24jan2005 3: 4: #include &lt;stdio.h&gt; 5: 6: int main() 7: { 8: int a[20] = {0};...</summary><published>2011-07-28T13:20:00Z</published><updated>2011-07-28T13:20:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119964.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119964.html"/><content type="html">&lt;p&gt;二分法查找&lt;/p&gt; &lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;// binary search of an integer array, this search is efficient for large arrays&lt;/span&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;// tested with PellesC       vegaseat     24jan2005&lt;/span&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;#include &amp;lt;stdio.h&amp;gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; main()&lt;span class="lnum"&gt;   7:  &lt;/span&gt;{&lt;span class="lnum"&gt;   8:  &lt;/span&gt;  &lt;span class="kwrd"&gt;int&lt;/span&gt; a[20] = {0}; &lt;span class="lnum"&gt;   9:  &lt;/span&gt;  &lt;span class="kwrd"&gt;int&lt;/span&gt; n, i, j, temp;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;  &lt;span class="kwrd"&gt;int&lt;/span&gt; *beg, *end, *mid, target;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;  &lt;span class="lnum"&gt;  12:  &lt;/span&gt;  printf(&lt;span class="str"&gt;" enter the total integers you want to enter (make it less then 20):\n"&lt;/span&gt;);&lt;span class="lnum"&gt;  13:  &lt;/span&gt;  scanf(&lt;span class="str"&gt;"%d"&lt;/span&gt;, &amp;amp;n);&lt;span class="lnum"&gt;  14:  &lt;/span&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (n &amp;gt;= 20) &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;   &lt;span class="rem"&gt;// ouch!&lt;/span&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;  printf(&lt;span class="str"&gt;" enter the integer array elements:\n"&lt;/span&gt; );&lt;span class="lnum"&gt;  16:  &lt;/span&gt;  &lt;span class="kwrd"&gt;for&lt;/span&gt;(i = 0; i &amp;lt; n; i++)&lt;span class="lnum"&gt;  17:  &lt;/span&gt;  {&lt;span class="lnum"&gt;  18:  &lt;/span&gt;    scanf(&lt;span class="str"&gt;"%d"&lt;/span&gt;, &amp;amp;a[i]);&lt;span class="lnum"&gt;  19:  &lt;/span&gt;  }&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    &lt;span class="lnum"&gt;  21:  &lt;/span&gt;  &lt;span class="rem"&gt;// sort the loaded array, a must for binary search! &lt;/span&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;  &lt;span class="rem"&gt;// you can apply qsort or other algorithms here&lt;/span&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;  &lt;span class="kwrd"&gt;for&lt;/span&gt;(i = 0; i &amp;lt; n-1; i++)&lt;span class="lnum"&gt;  24:  &lt;/span&gt;  {  &lt;span class="lnum"&gt;  25:  &lt;/span&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt;(j = 0; j &amp;lt; n-i-1; j++)&lt;span class="lnum"&gt;  26:  &lt;/span&gt;    {&lt;span class="lnum"&gt;  27:  &lt;/span&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (a[j+1] &amp;lt; a[j])&lt;span class="lnum"&gt;  28:  &lt;/span&gt;      {&lt;span class="lnum"&gt;  29:  &lt;/span&gt;        temp = a[j];&lt;span class="lnum"&gt;  30:  &lt;/span&gt;        a[j] = a[j+1];&lt;span class="lnum"&gt;  31:  &lt;/span&gt;        a[j+1] = temp;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;      }&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    }&lt;span class="lnum"&gt;  34:  &lt;/span&gt;  }&lt;span class="lnum"&gt;  35:  &lt;/span&gt;  printf(&lt;span class="str"&gt;" the sorted numbers are:"&lt;/span&gt;);&lt;span class="lnum"&gt;  36:  &lt;/span&gt;  &lt;span class="kwrd"&gt;for&lt;/span&gt;(i = 0; i &amp;lt; n; i++)&lt;span class="lnum"&gt;  37:  &lt;/span&gt;  {&lt;span class="lnum"&gt;  38:  &lt;/span&gt;    printf(&lt;span class="str"&gt;"%d "&lt;/span&gt;, a[i]);&lt;span class="lnum"&gt;  39:  &lt;/span&gt;  }&lt;span class="lnum"&gt;  40:  &lt;/span&gt;    &lt;span class="lnum"&gt;  41:  &lt;/span&gt;  &lt;span class="rem"&gt;// point to beginning and end of the array&lt;/span&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;  beg = &amp;amp;a[0];&lt;span class="lnum"&gt;  43:  &lt;/span&gt;  end = &amp;amp;a[n];  &lt;span class="rem"&gt;// use n = one element past the loaded array!&lt;/span&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;  printf(&lt;span class="str"&gt;"\n beg points to address %d and end to %d"&lt;/span&gt;,beg, end);  &lt;span class="rem"&gt;// test&lt;/span&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;  &lt;span class="rem"&gt;// mid should point somewhere in the middle of these addresses&lt;/span&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;  mid = beg += n/2;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;  printf(&lt;span class="str"&gt;"\n mid points to address %d"&lt;/span&gt;, mid);  &lt;span class="rem"&gt;// test&lt;/span&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;  &lt;span class="lnum"&gt;  50:  &lt;/span&gt;  printf(&lt;span class="str"&gt;"\n enter the number to be searched:"&lt;/span&gt;);&lt;span class="lnum"&gt;  51:  &lt;/span&gt;  scanf(&lt;span class="str"&gt;"%d"&lt;/span&gt;,&amp;amp;target);&lt;span class="lnum"&gt;  52:  &lt;/span&gt;  &lt;span class="lnum"&gt;  53:  &lt;/span&gt;  &lt;span class="rem"&gt;// binary search, there is an AND in the middle of while()!!!&lt;/span&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;  &lt;span class="kwrd"&gt;while&lt;/span&gt;((beg &amp;lt;= end) &amp;amp;&amp;amp; (*mid != target))&lt;span class="lnum"&gt;  55:  &lt;/span&gt;  {&lt;span class="lnum"&gt;  56:  &lt;/span&gt;    &lt;span class="rem"&gt;// is the target in lower or upper half?&lt;/span&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; (target &amp;lt; *mid)&lt;span class="lnum"&gt;  58:  &lt;/span&gt;      {&lt;span class="lnum"&gt;  59:  &lt;/span&gt;      end = mid - 1;     &lt;span class="rem"&gt;// new end&lt;/span&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;      n = n/2;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;      mid = beg += n/2;  &lt;span class="rem"&gt;// new middle&lt;/span&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;    }&lt;span class="lnum"&gt;  63:  &lt;/span&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;    {&lt;span class="lnum"&gt;  65:  &lt;/span&gt;      beg = mid + 1;     &lt;span class="rem"&gt;// new beginning&lt;/span&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;      n = n/2;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;      mid = beg += n/2;  &lt;span class="rem"&gt;// new middle      &lt;/span&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;    }&lt;span class="lnum"&gt;  69:  &lt;/span&gt;  }&lt;span class="lnum"&gt;  70:  &lt;/span&gt;  &lt;span class="lnum"&gt;  71:  &lt;/span&gt;  &lt;span class="rem"&gt;// did you find the target?&lt;/span&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (*mid == target)&lt;span class="lnum"&gt;  73:  &lt;/span&gt;  {&lt;span class="lnum"&gt;  74:  &lt;/span&gt;    printf(&lt;span class="str"&gt;"\n %d found!"&lt;/span&gt;, target);&lt;span class="lnum"&gt;  75:  &lt;/span&gt;  }&lt;span class="lnum"&gt;  76:  &lt;/span&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;span class="lnum"&gt;  77:  &lt;/span&gt;  {&lt;span class="lnum"&gt;  78:  &lt;/span&gt;    printf(&lt;span class="str"&gt;"\n %d not found!"&lt;/span&gt;, target);&lt;span class="lnum"&gt;  79:  &lt;/span&gt;  }&lt;span class="lnum"&gt;  80:  &lt;/span&gt;  &lt;span class="lnum"&gt;  81:  &lt;/span&gt;  getchar();  &lt;span class="rem"&gt;// trap enter&lt;/span&gt;&lt;span class="lnum"&gt;  82:  &lt;/span&gt;  getchar();  &lt;span class="rem"&gt;// wait&lt;/span&gt;&lt;span class="lnum"&gt;  83:  &lt;/span&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;&lt;span class="lnum"&gt;  84:  &lt;/span&gt;}&lt;span class="lnum"&gt;  85:  &lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2119964.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119964.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119959.html</id><title type="text">JAVA 上加密算法的实现用例</title><summary type="text">MD5/SHA1，DSA，DESede/DES，Diffie-Hellman 的使用 第 1 章基础知识 1.1. 单钥密码体制 单钥密码体制是一种传统的加密算法，是指信息的发送方和接收方共同使用同一把密钥进行加解密。 通常 , 使用的加密算法比较简便高效 , 密钥简短，加解密速度快，破译极其困难。但是加密的安全性依靠密钥保管的安全性 , 在公开的计算机网络上安全地传送和保管密钥是一个严峻的问题，...</summary><published>2011-07-28T13:19:00Z</published><updated>2011-07-28T13:19:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119959.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119959.html"/><content type="html">&lt;p&gt;&lt;em&gt;MD5/SHA1，DSA，DESede/DES，Diffie-Hellman 的使用&lt;/em&gt;  &lt;p&gt;&lt;a name="1"&gt;第 1 章基础知识&lt;/a&gt;  &lt;p&gt;&lt;a name="N10049"&gt;1.1. 单钥密码体制&lt;/a&gt;  &lt;p&gt;单钥密码体制是一种传统的加密算法，是指信息的发送方和接收方共同使用同一把密钥进行加解密。  &lt;p&gt;通常 , 使用的加密算法比较简便高效 , 密钥简短，加解密速度快，破译极其困难。但是加密的安全性依靠密钥保管的安全性 , 在公开的计算机网络上安全地传送和保管密钥是一个严峻的问题，并且如果在多用户的情况下密钥的保管安全性也是一个问题。  &lt;p&gt;单钥密码体制的代表是美国的 DES  &lt;p&gt;&lt;a name="N10058"&gt;1.2. 消息摘要&lt;/a&gt;  &lt;p&gt;一个消息摘要就是一个数据块的数字指纹。即对一个任意长度的一个数据块进行计算，产生一个唯一指印（对于 SHA1 是产生一个 20 字节的二进制数组）。  &lt;p&gt;消息摘要有两个基本属性：  &lt;ul&gt; &lt;li&gt;两个不同的报文难以生成相同的摘要  &lt;li&gt;难以对指定的摘要生成一个报文，而由该报文反推算出该指定的摘要 &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;代表：美国国家标准技术研究所的 SHA1 和麻省理工学院 Ronald Rivest 提出的 MD5  &lt;p&gt;&lt;a name="N10070"&gt;1.3. Diffie-Hellman 密钥一致协议&lt;/a&gt;  &lt;p&gt;密钥一致协议是由公开密钥密码体制的奠基人 Diffie 和 Hellman 所提出的一种思想。  &lt;p&gt;先决条件 , 允许两名用户在公开媒体上交换信息以生成"一致"的 , 可以共享的密钥  &lt;p&gt;代表：指数密钥一致协议 (Exponential Key Agreement Protocol)  &lt;p&gt;&lt;a name="N1007F"&gt;1.4. 非对称算法与公钥体系&lt;/a&gt;  &lt;p&gt;1976 年，Dittie 和 Hellman 为解决密钥管理问题，在他们的奠基性的工作"密码学的新方向"一文中，提出一种密钥交换协议，允许在不安全的媒体上通过通讯双方交换信息，安全地传送秘密密钥。在此新思想的基础上，很快出现了非对称密钥密码体制，即公钥密码体制。在公钥体制中，加密密钥不同于解密密钥，加密密钥公之于众，谁都可以使用；解密密钥只有解密人自己知道。它们分别称为公开密钥（Public key）和秘密密钥（Private key）。  &lt;p&gt;迄今为止的所有公钥密码体系中，RSA 系统是最著名、最多使用的一种。RSA 公开密钥密码系统是由 R.Rivest、A.Shamir 和 L.Adleman 俊教授于 1977 年提出的。RSA 的取名就是来自于这三位发明者的姓的第一个字母  &lt;p&gt;&lt;a name="N1008B"&gt;1.5. 数字签名&lt;/a&gt;  &lt;p&gt;所谓数字签名就是信息发送者用其私钥对从所传报文中提取出的特征数据（或称数字指纹）进行 RSA 算法操作，以保证发信人无法抵赖曾发过该信息（即不可抵赖性），同时也确保信息报文在经签名后末被篡改（即完整性）。当信息接收者收到报文后，就可以用发送者的公钥对数字签名进行验证。　  &lt;p&gt;在数字签名中有重要作用的数字指纹是通过一类特殊的散列函数（HASH 函数）生成的，对这些 HASH 函数的特殊要求是：  &lt;ol&gt; &lt;li&gt;接受的输入报文数据没有长度限制；  &lt;li&gt;对任何输入报文数据生成固定长度的摘要（数字指纹）输出  &lt;li&gt;从报文能方便地算出摘要；  &lt;li&gt;难以对指定的摘要生成一个报文，而由该报文反推算出该指定的摘要；  &lt;li&gt;两个不同的报文难以生成相同的摘要 &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;代表：DSA  &lt;p&gt;&lt;a href="http://www.ibm.com/developerworks/cn/java/l-security/#ibm-pcon"&gt;回页首&lt;/a&gt;  &lt;p&gt;&lt;a name="2"&gt;第 2 章在 JAVA 中的实现&lt;/a&gt;  &lt;p&gt;&lt;a name="N100B4"&gt;2.1. 相关&lt;/a&gt;  &lt;p&gt;Diffie-Hellman 密钥一致协议和 DES 程序需要 JCE 工具库的支持 , 可以到 &lt;a href="http://java.sun.com/security/index.html"&gt;http://java.sun.com/security/index.html&lt;/a&gt; 下载 JCE, 并进行安装。简易安装把 jce1.2.1\lib 下的所有内容复制到 %java_home%\lib\ext 下 , 如果没有 ext 目录自行建立 , 再把 jce1_2_1.jar 和 sunjce_provider.jar 添加到 CLASSPATH 内 , 更详细说明请看相应用户手册  &lt;p&gt;&lt;a name="N100C1"&gt;2.2. 消息摘要 MD5 和 SHA 的使用&lt;/a&gt;  &lt;p&gt;使用方法 :  &lt;p&gt;首先用生成一个 MessageDigest 类 , 确定计算方法  &lt;p&gt;java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");  &lt;p&gt;添加要进行计算摘要的信息  &lt;p&gt;alga.update(myinfo.getBytes());  &lt;p&gt;计算出摘要  &lt;p&gt;byte[] digesta=alga.digest();  &lt;p&gt;发送给其他人你的信息和摘要  &lt;p&gt;其他人用相同的方法初始化 , 添加信息 , 最后进行比较摘要是否相同  &lt;p&gt;algb.isEqual(digesta,algb.digest())  &lt;p&gt;相关 AIP  &lt;p&gt;java.security.MessageDigest 类  &lt;p&gt;static getInstance(String algorithm)  &lt;p&gt;返回一个 MessageDigest 对象 , 它实现指定的算法  &lt;p&gt;参数 : 算法名 , 如 SHA-1 或 MD5  &lt;p&gt;void update (byte input)  &lt;p&gt;void update (byte[] input)  &lt;p&gt;void update(byte[] input, int offset, int len)  &lt;p&gt;添加要进行计算摘要的信息  &lt;p&gt;byte[] digest()  &lt;p&gt;完成计算 , 返回计算得到的摘要 ( 对于 MD5 是 16 位 ,SHA 是 20 位 )  &lt;p&gt;void reset()  &lt;p&gt;复位  &lt;p&gt;static boolean isEqual(byte[] digesta, byte[] digestb)  &lt;p&gt;比效两个摘要是否相同  &lt;p&gt;代码：import java.security.*; &lt;br/&gt; public class myDigest { &lt;br/&gt;  public static void main(String[] args)  { &lt;br/&gt;    myDigest my=new myDigest(); &lt;br/&gt;    my.testDigest(); &lt;br/&gt;  } &lt;br/&gt;  public void testDigest() &lt;br/&gt;  { &lt;br/&gt;   try { &lt;br/&gt;     String myinfo="我的测试信息"; &lt;br/&gt;    //java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5"); &lt;br/&gt;      java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1"); &lt;br/&gt;      alga.update(myinfo.getBytes()); &lt;br/&gt;      byte[] digesta=alga.digest(); &lt;br/&gt;      System.out.println("本信息摘要是 :"+byte2hex(digesta)); &lt;br/&gt;      // 通过某中方式传给其他人你的信息 (myinfo) 和摘要 (digesta) 对方可以判断是否更改或传输正常&lt;br/&gt;      java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1"); &lt;br/&gt;      algb.update(myinfo.getBytes()); &lt;br/&gt;      if (algb.isEqual(digesta,algb.digest())) { &lt;br/&gt;         System.out.println("信息检查正常"); &lt;br/&gt;       } &lt;br/&gt;       else &lt;br/&gt;        { &lt;br/&gt;          System.out.println("摘要不相同"); &lt;br/&gt;         } &lt;br/&gt;   } &lt;br/&gt;   catch (java.security.NoSuchAlgorithmException ex) { &lt;br/&gt;     System.out.println("非法摘要算法"); &lt;br/&gt;   } &lt;br/&gt;  } &lt;br/&gt;  public String byte2hex(byte[] b) // 二行制转字符串&lt;br/&gt;    { &lt;br/&gt;     String hs=""; &lt;br/&gt;     String stmp=""; &lt;br/&gt;     for (int n=0;n&amp;lt;b.length;n++) &lt;br/&gt;      { &lt;br/&gt;       stmp=(java.lang.Integer.toHexString(b[n] &amp;amp; 0XFF)); &lt;br/&gt;       if (stmp.length()==1) hs=hs+"0"+stmp; &lt;br/&gt;       else hs=hs+stmp; &lt;br/&gt;       if (n&amp;lt;b.length-1)  hs=hs+":"; &lt;br/&gt;      } &lt;br/&gt;     return hs.toUpperCase(); &lt;br/&gt;    } &lt;br/&gt; }&lt;p&gt;&lt;a name="N10119"&gt;2.3. 数字签名 DSA&lt;/a&gt; &lt;ol&gt;&lt;li&gt;对于一个用户来讲首先要生成他的密钥对 , 并且分别保存 &lt;p&gt;生成一个 KeyPairGenerator 实例java.security.KeyPairGenerator keygen=java.security.KeyPairGenerator.getInstance("DSA");&lt;br/&gt;&lt;br/&gt;//如果设定随机产生器就用如相代码初始化&lt;br/&gt;SecureRandom secrand=new SecureRandom(); &lt;br/&gt;secrand.setSeed("tttt".getBytes()); // 初始化随机产生器&lt;br/&gt;keygen.initialize(512,secrand);     // 初始化密钥生成器&lt;br/&gt;&lt;br/&gt;//否则&lt;br/&gt;keygen.initialize(512); &lt;br/&gt;    &lt;br/&gt;//生成密钥公钥 pubkey 和私钥 prikey &lt;br/&gt;KeyPair keys=keygen.generateKeyPair(); // 生成密钥组&lt;br/&gt;PublicKey pubkey=keys.getPublic(); &lt;br/&gt;PrivateKey prikey=keys.getPrivate(); &lt;br/&gt;    &lt;br/&gt;//分别保存在 myprikey.dat 和 mypubkey.dat 中 , 以便下次不在生成&lt;br/&gt;//( 生成密钥对的时间比较长&lt;br/&gt;java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(&lt;br/&gt;    new java.io.FileOutputStream("myprikey.dat")); &lt;br/&gt;out.writeObject(prikey); &lt;br/&gt;out.close(); &lt;br/&gt;out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));&lt;br/&gt;out.writeObject(pubkey); &lt;br/&gt;out.close(); &lt;br/&gt;&lt;li&gt;用他私人密钥 (prikey) 对他所确认的信息 (info) 进行数字签名产生一个签名数组 &lt;p&gt;从文件中读入私人密钥 (prikey)java.io.ObjectInputStream in=new java.io.ObjectInputStream(&lt;br/&gt;    new java.io.FileInputStream("myprikey.dat")); &lt;br/&gt;PrivateKey myprikey=(PrivateKey)in.readObject(); &lt;br/&gt;in.close(); &lt;br/&gt;初始一个 Signature 对象 , 并用私钥对信息签名&lt;br/&gt;java.security.Signature signet=java.security.Signature.getInstance("DSA"); &lt;br/&gt;signet.initSign(myprikey); &lt;br/&gt;signet.update(myinfo.getBytes()); &lt;br/&gt;byte[] signed=signet.sign(); &lt;br/&gt;&lt;br/&gt;把信息和签名保存在一个文件中 (myinfo.dat) &lt;br/&gt;java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(&lt;br/&gt;    new java.io.FileOutputStream("myinfo.dat")); &lt;br/&gt;out.writeObject(myinfo); &lt;br/&gt;out.writeObject(signed); &lt;br/&gt;out.close(); &lt;br/&gt;把他的公钥的信息及签名发给其它用户&lt;br/&gt;&lt;li&gt;其他用户用他的公共密钥 (pubkey) 和签名 (signed) 和信息 (info) 进行验证是否由他签名的信息 &lt;p&gt;读入公钥 &lt;br&gt;&lt;code&gt;java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat")); &lt;br&gt;PublicKey pubkey=(PublicKey)in.readObject(); &lt;br&gt;in.close(); &lt;/code&gt;&lt;p&gt;读入签名和信息 &lt;br&gt;&lt;code&gt;in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat")); &lt;br&gt;String info=(String)in.readObject(); &lt;br&gt;byte[] signed=(byte[])in.readObject(); &lt;br&gt;in.close(); &lt;/code&gt;&lt;p&gt;初始一个 Signature 对象 , 并用公钥和签名进行验证 &lt;br&gt;&lt;code&gt;java.security.Signature signetcheck=java.security.Signature.getInstance("DSA"); &lt;br&gt;signetcheck.initVerify(pubkey); &lt;br&gt;signetcheck.update(info.getBytes()); &lt;br&gt;if (signetcheck.verify(signed)) { System.out.println("签名正常");} &lt;/code&gt;&lt;p&gt;对于密钥的保存本文是用对象流的方式保存和传送的 , 也可可以用编码的方式保存 . 注意要 &lt;br&gt;&lt;code&gt;import java.security.spec.* &lt;br&gt;import java.security.* &lt;/code&gt;&lt;p&gt;具休说明如下 &lt;ul&gt;&lt;li&gt;public key 是用 X.509 编码的 , 例码如下 :  byte[] bobEncodedPubKey=mypublic.getEncoded(); // 生成编码&lt;br/&gt;   // 传送二进制编码&lt;br/&gt;   // 以下代码转换编码为相应 key 对象&lt;br/&gt;   X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey); &lt;br/&gt;   KeyFactory keyFactory = KeyFactory.getInstance("DSA"); &lt;br/&gt;   PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec); &lt;br/&gt;&lt;li&gt;对于 Private key 是用 PKCS#8 编码 , 例码如下 : byte[] bPKCS=myprikey.getEncoded(); &lt;br/&gt;  // 传送二进制编码&lt;br/&gt;  // 以下代码转换编码为相应 key 对象&lt;br/&gt;  PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS); &lt;br/&gt;  KeyFactory keyf=KeyFactory.getInstance("DSA"); &lt;br/&gt;  PrivateKey otherprikey=keyf.generatePrivate(priPKCS8); &lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;常用 API &lt;p&gt;java.security.KeyPairGenerator 密钥生成器类 &lt;br&gt;public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException &lt;br&gt;以指定的算法返回一个 KeyPairGenerator 对象 &lt;br&gt;参数 : algorithm 算法名 . 如 :"DSA","RSA" &lt;p&gt;public void initialize(int keysize) &lt;p&gt;以指定的长度初始化 KeyPairGenerator 对象 , 如果没有初始化系统以 1024 长度默认设置 &lt;p&gt;参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间，且必须为 64 的倍数 &lt;p&gt;public void initialize(int keysize, SecureRandom random) &lt;br&gt;以指定的长度初始化和随机发生器初始化 KeyPairGenerator 对象 &lt;br&gt;参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间，且必须为 64 的倍数 &lt;br&gt;random 一个随机位的来源 ( 对于 initialize(int keysize) 使用了默认随机器 &lt;p&gt;public abstract KeyPair generateKeyPair() &lt;br&gt;产生新密钥对 &lt;p&gt;java.security.KeyPair 密钥对类 &lt;br&gt;public PrivateKey getPrivate() &lt;br&gt;返回私钥 &lt;p&gt;public PublicKey getPublic() &lt;br&gt;返回公钥 &lt;p&gt;java.security.Signature 签名类 &lt;br&gt;public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException &lt;br&gt;返回一个指定算法的 Signature 对象 &lt;br&gt;参数 algorithm 如 :"DSA" &lt;p&gt;public final void initSign(PrivateKey privateKey) &lt;br&gt;throws InvalidKeyException &lt;br&gt;用指定的私钥初始化 &lt;br&gt;参数 :privateKey 所进行签名时用的私钥 &lt;p&gt;public final void update(byte data) &lt;br&gt;throws SignatureException &lt;br&gt;public final void update(byte[] data) &lt;br&gt;throws SignatureException &lt;br&gt;public final void update(byte[] data, int off, int len) &lt;br&gt;throws SignatureException &lt;br&gt;添加要签名的信息 &lt;p&gt;public final byte[] sign() &lt;br&gt;throws SignatureException &lt;br&gt;返回签名的数组 , 前提是 initSign 和 update &lt;p&gt;public final void initVerify(PublicKey publicKey) &lt;br&gt;throws InvalidKeyException &lt;br&gt;用指定的公钥初始化 &lt;br&gt;参数 :publicKey 验证时用的公钥 &lt;p&gt;public final boolean verify(byte[] signature) &lt;br&gt;throws SignatureException &lt;br&gt;验证签名是否有效 , 前提是已经 initVerify 初始化 &lt;br&gt;参数 : signature 签名数组  import java.security.*; &lt;br/&gt; import java.security.spec.*; &lt;br/&gt; public class testdsa { &lt;br/&gt;  &lt;br/&gt;  public static void main(String[] args) throws java.security.NoSuchAlgorithmException,&lt;br/&gt;  java.lang.Exception { &lt;br/&gt;        testdsa my=new testdsa(); &lt;br/&gt;        my.run(); &lt;br/&gt;  } &lt;br/&gt;  public void run() &lt;br/&gt;  { &lt;br/&gt;  // 数字签名生成密钥&lt;br/&gt;  // 第一步生成密钥对 , 如果已经生成过 , 本过程就可以跳过 , &lt;br/&gt;  // 对用户来讲 myprikey.dat 要保存在本地&lt;br/&gt;  // 而 mypubkey.dat 给发布给其它用户&lt;br/&gt;   if ((new java.io.File("myprikey.dat")).exists()==false) { &lt;br/&gt;       if (generatekey()==false) { &lt;br/&gt;           System.out.println("生成密钥对败"); &lt;br/&gt;           return; &lt;br/&gt;          }; &lt;br/&gt;        } &lt;br/&gt; // 第二步 , 此用户&lt;br/&gt; // 从文件中读入私钥 , 对一个字符串进行签名后保存在一个文件 (myinfo.dat) 中&lt;br/&gt; // 并且再把 myinfo.dat 发送出去&lt;br/&gt; // 为了方便数字签名也放进了 myifno.dat 文件中 , 当然也可分别发送&lt;br/&gt;  try { &lt;br/&gt;  java.io.ObjectInputStream in=new java.io.ObjectInputStream(&lt;br/&gt;  new java.io.FileInputStream("myprikey.dat")); &lt;br/&gt;  PrivateKey myprikey=(PrivateKey)in.readObject(); &lt;br/&gt;  in.close(); &lt;br/&gt; // java.security.spec.X509EncodedKeySpec pubX509=&lt;br/&gt; //   new java.security.spec.X509EncodedKeySpec(bX509); &lt;br/&gt; //java.security.spec.X509EncodedKeySpec pubkeyEncode=&lt;br/&gt; //   java.security.spec.X509EncodedKeySpec &lt;br/&gt;  String myinfo="这是我的信息";    // 要签名的信息&lt;br/&gt;  // 用私钥对信息生成数字签名&lt;br/&gt;  java.security.Signature signet=java.security.Signature.getInstance("DSA");&lt;br/&gt;  signet.initSign(myprikey); &lt;br/&gt;  signet.update(myinfo.getBytes()); &lt;br/&gt;  byte[] signed=signet.sign();  // 对信息的数字签名&lt;br/&gt;  System.out.println("signed( 签名内容 )="+byte2hex(signed)); &lt;br/&gt; // 把信息和数字签名保存在一个文件中&lt;br/&gt;  java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(&lt;br/&gt;  new java.io.FileOutputStream("myinfo.dat")); &lt;br/&gt;  out.writeObject(myinfo); &lt;br/&gt;  out.writeObject(signed); &lt;br/&gt;  out.close(); &lt;br/&gt;  System.out.println("签名并生成文件成功"); &lt;br/&gt;  } &lt;br/&gt;  catch (java.lang.Exception e) { &lt;br/&gt;    e.printStackTrace(); &lt;br/&gt;    System.out.println("签名并生成文件失败"); &lt;br/&gt;  }; &lt;br/&gt;  // 第三步&lt;br/&gt;  // 其他人通过公共方式得到此户的公钥和文件&lt;br/&gt;  // 其他人用此户的公钥 , 对文件进行检查 , 如果成功说明是此用户发布的信息 . &lt;br/&gt;  // &lt;br/&gt;  try { &lt;br/&gt;   java.io.ObjectInputStream in=new java.io.ObjectInputStream(&lt;br/&gt;   new java.io.FileInputStream("mypubkey.dat")); &lt;br/&gt;   PublicKey pubkey=(PublicKey)in.readObject(); &lt;br/&gt;   in.close(); &lt;br/&gt;   System.out.println(pubkey.getFormat()); &lt;br/&gt;   in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat")); &lt;br/&gt;   String info=(String)in.readObject(); &lt;br/&gt;   byte[] signed=(byte[])in.readObject(); &lt;br/&gt;   in.close(); &lt;br/&gt;  java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");&lt;br/&gt;  signetcheck.initVerify(pubkey); &lt;br/&gt;  signetcheck.update(info.getBytes()); &lt;br/&gt;  if (signetcheck.verify(signed)) { &lt;br/&gt;  System.out.println("info="+info); &lt;br/&gt;   System.out.println("签名正常"); &lt;br/&gt;  } &lt;br/&gt;  else  System.out.println("非签名正常"); &lt;br/&gt;  } &lt;br/&gt;  catch (java.lang.Exception e) {e.printStackTrace();}; &lt;br/&gt;  } &lt;br/&gt;  // 生成一对文件 myprikey.dat 和 mypubkey.dat--- 私钥和公钥 , &lt;br/&gt;  // 公钥要用户发送 ( 文件 , 网络等方法 ) 给其它用户 , 私钥保存在本地&lt;br/&gt;  public boolean generatekey() &lt;br/&gt;  { &lt;br/&gt;    try { &lt;br/&gt;  java.security.KeyPairGenerator keygen = &lt;br/&gt;  java.security.KeyPairGenerator.getInstance("DSA");&lt;br/&gt; // SecureRandom secrand=new SecureRandom(); &lt;br/&gt; // secrand.setSeed("tttt".getBytes()); // 初始化随机产生器&lt;br/&gt; // keygen.initialize(576,secrand);     // 初始化密钥生成器&lt;br/&gt;  keygen.initialize(512); &lt;br/&gt;  KeyPair keys=keygen.genKeyPair(); &lt;br/&gt; //  KeyPair keys=keygen.generateKeyPair(); // 生成密钥组&lt;br/&gt;  PublicKey pubkey=keys.getPublic(); &lt;br/&gt;  PrivateKey prikey=keys.getPrivate(); &lt;br/&gt;  java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(&lt;br/&gt;  new java.io.FileOutputStream("myprikey.dat")); &lt;br/&gt;  out.writeObject(prikey); &lt;br/&gt;  out.close(); &lt;br/&gt;  System.out.println("写入对象 prikeys ok"); &lt;br/&gt;  out=new java.io.ObjectOutputStream(&lt;br/&gt;  new java.io.FileOutputStream("mypubkey.dat")); &lt;br/&gt;   out.writeObject(pubkey); &lt;br/&gt;   out.close(); &lt;br/&gt;   System.out.println("写入对象 pubkeys ok"); &lt;br/&gt;   System.out.println("生成密钥对成功"); &lt;br/&gt;   return true; &lt;br/&gt;  } &lt;br/&gt;  catch (java.lang.Exception e) { &lt;br/&gt;   e.printStackTrace(); &lt;br/&gt;   System.out.println("生成密钥对失败"); &lt;br/&gt;   return false; &lt;br/&gt;   }; &lt;br/&gt;  } &lt;br/&gt;  public String byte2hex(byte[] b) &lt;br/&gt;    { &lt;br/&gt;     String hs=""; &lt;br/&gt;     String stmp=""; &lt;br/&gt;     for (int n=0;n&amp;lt;b.length;n++) &lt;br/&gt;      { &lt;br/&gt;       stmp=(java.lang.Integer.toHexString(b[n] &amp;amp; 0XFF)); &lt;br/&gt;       if (stmp.length()==1) hs=hs+"0"+stmp; &lt;br/&gt;       else hs=hs+stmp; &lt;br/&gt;       if (n&amp;lt;b.length-1)  hs=hs+":"; &lt;br/&gt;      } &lt;br/&gt;     return hs.toUpperCase(); &lt;br/&gt;    } &lt;br/&gt; }&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;a name="N101FC"&gt;2.4. DESede/DES 对称算法&lt;/a&gt; &lt;p&gt;首先生成密钥 , 并保存 ( 这里并没的保存的代码 , 可参考 DSA 中的方法 ) &lt;p&gt;KeyGenerator keygen = KeyGenerator.getInstance(Algorithm); &lt;p&gt;SecretKey deskey = keygen.generateKey(); &lt;p&gt;用密钥加密明文 (myinfo), 生成密文 (cipherByte) &lt;p&gt;Cipher c1 = Cipher.getInstance(Algorithm); &lt;p&gt;c1.init(Cipher.ENCRYPT_MODE,deskey); &lt;p&gt;byte[] cipherByte=c1.doFinal(myinfo.getBytes()); &lt;p&gt;传送密文和密钥 , 本文没有相应代码可参考 DSA &lt;p&gt;............. &lt;p&gt;用密钥解密密文 &lt;p&gt;c1 = Cipher.getInstance(Algorithm); &lt;p&gt;c1.init(Cipher.DECRYPT_MODE,deskey); &lt;p&gt;byte[] clearByte=c1.doFinal(cipherByte); &lt;p&gt;相对来说对称密钥的使用是很简单的 , 对于 JCE 来讲支技 DES,DESede,Blowfish 三种加密术 &lt;p&gt;对于密钥的保存各传送可使用对象流或者用二进制编码 , 相关参考代码如下SecretKey deskey = keygen.generateKey(); &lt;br/&gt;byte[] desEncode=deskey.getEncoded(); &lt;br/&gt;javax.crypto.spec.SecretKeySpec destmp =&lt;br/&gt;    new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm);&lt;br/&gt;SecretKey mydeskey=destmp;&lt;p&gt;相关 API &lt;p&gt;KeyGenerator 在 DSA 中已经说明 , 在添加 JCE 后在 instance 进可以如下参数 &lt;p&gt;DES,DESede,Blowfish,HmacMD5,HmacSHA1 &lt;p&gt;javax.crypto.Cipher 加 / 解密器public static final Cipher getInstance(java.lang.String transformation) &lt;br/&gt;                                throws java.security.NoSuchAlgorithmException, &lt;br/&gt;                                       NoSuchPaddingException&lt;p&gt;返回一个指定方法的 Cipher 对象 &lt;p&gt;参数 :transformation 方法名 ( 可用 DES,DESede,Blowfish) &lt;p&gt;public final void init(int opmode, java.security.Key key) &lt;br&gt;throws java.security.InvalidKeyException &lt;p&gt;用指定的密钥和模式初始化 Cipher 对象 &lt;p&gt;参数 :opmode 方式 (ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE) &lt;p&gt;key 密钥public final byte[] doFinal(byte[] input) &lt;br/&gt;                     throws java.lang.IllegalStateException, &lt;br/&gt;                            IllegalBlockSizeException, &lt;br/&gt;                            BadPaddingException &lt;br/&gt;&lt;p&gt;对 input 内的串 , 进行编码处理 , 返回处理后二进制串 , 是返回解密文还是加解文由 init 时的 opmode 决定 &lt;p&gt;注意 : 本方法的执行前如果有 update, 是对 updat 和本次 input 全部处理 , 否则是本 inout 的内容/* &lt;br/&gt;安全程序 DESede/DES 测试&lt;br/&gt; */ &lt;br/&gt; import java.security.*; &lt;br/&gt; import javax.crypto.*; &lt;br/&gt; public class testdes { &lt;br/&gt; public static void main(String[] args){ &lt;br/&gt;    testdes my=new testdes(); &lt;br/&gt;    my.run(); &lt;br/&gt;  } &lt;br/&gt; public  void run() { &lt;br/&gt; // 添加新安全算法 , 如果用 JCE 就要把它添加进去&lt;br/&gt; Security.addProvider(new com.sun.crypto.provider.SunJCE()); &lt;br/&gt; String Algorithm="DES"; // 定义 加密算法 , 可用 DES,DESede,Blowfish &lt;br/&gt; String myinfo="要加密的信息"; &lt;br/&gt;   try { &lt;br/&gt;   // 生成密钥&lt;br/&gt;   KeyGenerator keygen = KeyGenerator.getInstance(Algorithm); &lt;br/&gt;   SecretKey deskey = keygen.generateKey(); &lt;br/&gt;   // 加密&lt;br/&gt;   System.out.println("加密前的二进串 :"+byte2hex(myinfo.getBytes())); &lt;br/&gt;   System.out.println("加密前的信息 :"+myinfo); &lt;br/&gt;   Cipher c1 = Cipher.getInstance(Algorithm); &lt;br/&gt;   c1.init(Cipher.ENCRYPT_MODE,deskey); &lt;br/&gt;   byte[] cipherByte=c1.doFinal(myinfo.getBytes()); &lt;br/&gt;    System.out.println("加密后的二进串 :"+byte2hex(cipherByte)); &lt;br/&gt;   // 解密&lt;br/&gt;   c1 = Cipher.getInstance(Algorithm); &lt;br/&gt;   c1.init(Cipher.DECRYPT_MODE,deskey); &lt;br/&gt;   byte[] clearByte=c1.doFinal(cipherByte); &lt;br/&gt;   System.out.println("解密后的二进串 :"+byte2hex(clearByte)); &lt;br/&gt;   System.out.println("解密后的信息 :"+(new String(clearByte))); &lt;br/&gt;  } &lt;br/&gt;   catch (java.security.NoSuchAlgorithmException e1) {e1.printStackTrace();} &lt;br/&gt;   catch (javax.crypto.NoSuchPaddingException e2) {e2.printStackTrace();} &lt;br/&gt;   catch (java.lang.Exception e3) {e3.printStackTrace();} &lt;br/&gt;  } &lt;br/&gt; public String byte2hex(byte[] b) // 二行制转字符串&lt;br/&gt;    { &lt;br/&gt;     String hs=""; &lt;br/&gt;     String stmp=""; &lt;br/&gt;     for (int n=0;n&amp;lt;b.length;n++) &lt;br/&gt;      { &lt;br/&gt;       stmp=(java.lang.Integer.toHexString(b[n] &amp;amp; 0XFF)); &lt;br/&gt;       if (stmp.length()==1) hs=hs+"0"+stmp; &lt;br/&gt;       else hs=hs+stmp; &lt;br/&gt;       if (n&amp;lt;b.length-1)  hs=hs+":"; &lt;br/&gt;      } &lt;br/&gt;     return hs.toUpperCase(); &lt;br/&gt;    } &lt;br/&gt; }&lt;p&gt;&lt;a name="N10267"&gt;2.5. Diffie-Hellman 密钥一致协议&lt;/a&gt; &lt;p&gt;公开密钥密码体制的奠基人 Diffie 和 Hellman 所提出的 "指数密钥一致协议"(Exponential Key Agreement Protocol), 该协议不要求别的安全性先决条件 , 允许两名用户在公开媒体上交换信息以生成"一致"的 , 可以共享的密钥。在 JCE 的中实现用户 alice 生成 DH 类型的密钥对 , 如果长度用 1024 生成的时间请 , 推荐第一次生成后保存 DHParameterSpec, 以便下次使用直接初始化 . 使其速度加快System.out.println("ALICE: 产生 DH 对 ..."); &lt;br/&gt; KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); &lt;br/&gt; aliceKpairGen.initialize(512); &lt;br/&gt; KeyPair aliceKpair = aliceKpairGen.generateKeyPair();&lt;p&gt;alice 生成公钥发送组 bobbyte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();&lt;p&gt;bob 从 alice 发送来的公钥中读出 DH 密钥对的初始参数生成 bob 的 DH 密钥对 &lt;p&gt;注意这一步一定要做 , 要保证每个用户用相同的初始参数生成的  DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); &lt;br/&gt;    KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); &lt;br/&gt;    bobKpairGen.initialize(dhParamSpec); &lt;br/&gt;    KeyPair bobKpair = bobKpairGen.generateKeyPair();&lt;p&gt;bob 根据 alice 的公钥生成本地的 DES 密钥  KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); &lt;br/&gt;    bobKeyAgree.init(bobKpair.getPrivate()); &lt;br/&gt;    bobKeyAgree.doPhase(alicePubKey, true); &lt;br/&gt;    SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");&lt;p&gt;bob 已经生成了他的 DES 密钥 , 他现把他的公钥发给 alice,     byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();&lt;p&gt;alice 根据 bob 的公钥生成本地的 DES 密钥      ,,,,,, 解码&lt;br/&gt;    KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); &lt;br/&gt;    aliceKeyAgree.init(aliceKpair.getPrivate()); &lt;br/&gt;    aliceKeyAgree.doPhase(bobPubKey, true); &lt;br/&gt;    SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");&lt;p&gt;bob 和 alice 能过这个过程就生成了相同的 DES 密钥 , 在这种基础就可进行安全能信 &lt;p&gt;&lt;strong&gt;常用 API&lt;/strong&gt; &lt;p&gt;java.security.KeyPairGenerator 密钥生成器类 &lt;br&gt;public static KeyPairGenerator getInstance(String algorithm) &lt;br&gt;throws NoSuchAlgorithmException &lt;br&gt;以指定的算法返回一个 KeyPairGenerator 对象 &lt;br&gt;参数 : algorithm 算法名 . 如 : 原来是 DSA, 现在添加了 DiffieHellman(DH) &lt;p&gt;public void initialize(int keysize) &lt;br&gt;以指定的长度初始化 KeyPairGenerator 对象 , 如果没有初始化系统以 1024 长度默认设置 &lt;br&gt;参数 :keysize 算法位长 . 其范围必须在 512 到 1024 之间，且必须为 64 的倍数 &lt;br&gt;注意 : 如果用 1024 生长的时间很长 , 最好生成一次后就保存 , 下次就不用生成了 &lt;p&gt;public void initialize(AlgorithmParameterSpec params) &lt;br&gt;throws InvalidAlgorithmParameterException &lt;br&gt;以指定参数初始化 &lt;p&gt;javax.crypto.interfaces.DHPublicKey &lt;br&gt;public DHParameterSpec getParams() &lt;br&gt;返回 &lt;br&gt;java.security.KeyFactory &lt;p&gt;public static KeyFactory getInstance(String algorithm) &lt;br&gt;throws NoSuchAlgorithmException &lt;br&gt;以指定的算法返回一个 KeyFactory &lt;br&gt;参数 : algorithm 算法名 :DSH,DH &lt;p&gt;public final PublicKey generatePublic(KeySpec keySpec) &lt;br&gt;throws InvalidKeySpecException &lt;br&gt;根据指定的 key 说明 , 返回一个 PublicKey 对象 &lt;p&gt;java.security.spec.X509EncodedKeySpec &lt;br&gt;public X509EncodedKeySpec(byte[] encodedKey) &lt;br&gt;根据指定的二进制编码的字串生成一个 key 的说明 &lt;br&gt;参数 :encodedKey 二进制编码的字串 ( 一般能过 PublicKey.getEncoded() 生成 ) &lt;br&gt;javax.crypto.KeyAgreement 密码一至类 &lt;p&gt;public static final KeyAgreement getInstance(java.lang.String algorithm) &lt;br&gt;throws java.security.NoSuchAlgorithmException &lt;br&gt;返回一个指定算法的 KeyAgreement 对象 &lt;br&gt;参数 :algorithm 算法名 , 现在只能是 DiffieHellman(DH) &lt;p&gt;public final void init(java.security.Key key) &lt;br&gt;throws java.security.InvalidKeyException &lt;br&gt;用指定的私钥初始化 &lt;br&gt;参数 :key 一个私钥 &lt;p&gt;public final java.security.Key doPhase(java.security.Key key, &lt;br&gt;boolean lastPhase) &lt;br&gt;throws java.security.InvalidKeyException, &lt;br&gt;java.lang.IllegalStateException &lt;br&gt;用指定的公钥进行定位 ,lastPhase 确定这是否是最后一个公钥 , 对于两个用户的 &lt;br&gt;情况下就可以多次定次 , 最后确定 &lt;br&gt;参数 :key 公钥 &lt;br&gt;lastPhase 是否最后公钥 &lt;p&gt;public final SecretKey generateSecret(java.lang.String algorithm) &lt;br&gt;throws java.lang.IllegalStateException, &lt;br&gt;java.security.NoSuchAlgorithmException, &lt;br&gt;java.security.InvalidKeyException &lt;br&gt;根据指定的算法生成密钥 &lt;br&gt;参数 :algorithm 加密算法 ( 可用 DES,DESede,Blowfish) */ &lt;br/&gt; import java.io.*; &lt;br/&gt; import java.math.BigInteger; &lt;br/&gt; import java.security.*; &lt;br/&gt; import java.security.spec.*; &lt;br/&gt; import java.security.interfaces.*; &lt;br/&gt; import javax.crypto.*; &lt;br/&gt; import javax.crypto.spec.*; &lt;br/&gt; import javax.crypto.interfaces.*; &lt;br/&gt; import com.sun.crypto.provider.SunJCE; &lt;br/&gt; public class testDHKey { &lt;br/&gt;    public static void main(String argv[]) { &lt;br/&gt;    try { &lt;br/&gt;        testDHKey my= new testDHKey(); &lt;br/&gt;        my.run(); &lt;br/&gt;    } catch (Exception e) { &lt;br/&gt;        System.err.println(e); &lt;br/&gt;    } &lt;br/&gt;    } &lt;br/&gt;    private void run() throws Exception { &lt;br/&gt;        Security.addProvider(new com.sun.crypto.provider.SunJCE()); &lt;br/&gt;    System.out.println("ALICE: 产生 DH 对 ..."); &lt;br/&gt;    KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH"); &lt;br/&gt;        aliceKpairGen.initialize(512); &lt;br/&gt;    KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); // 生成时间长&lt;br/&gt;        // 张三 (Alice) 生成公共密钥 alicePubKeyEnc 并发送给李四 (Bob) , &lt;br/&gt;        // 比如用文件方式 ,socket..... &lt;br/&gt;    byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded(); &lt;br/&gt;       //bob 接收到 alice 的编码后的公钥 , 将其解码&lt;br/&gt;    KeyFactory bobKeyFac = KeyFactory.getInstance("DH"); &lt;br/&gt;    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec  (alicePubKeyEnc); &lt;br/&gt;    PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); &lt;br/&gt;        System.out.println("alice 公钥 bob 解码成功"); &lt;br/&gt;     // bob 必须用相同的参数初始化的他的 DH KEY 对 , 所以要从 Alice 发给他的公开密钥 , &lt;br/&gt;         // 中读出参数 , 再用这个参数初始化他的 DH key 对&lt;br/&gt;         // 从 alicePubKye 中取 alice 初始化时用的参数&lt;br/&gt;    DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); &lt;br/&gt;    KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH"); &lt;br/&gt;    bobKpairGen.initialize(dhParamSpec); &lt;br/&gt;    KeyPair bobKpair = bobKpairGen.generateKeyPair(); &lt;br/&gt;        System.out.println("BOB: 生成 DH key 对成功"); &lt;br/&gt;    KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH"); &lt;br/&gt;    bobKeyAgree.init(bobKpair.getPrivate()); &lt;br/&gt;        System.out.println("BOB: 初始化本地 key 成功"); &lt;br/&gt;        // 李四 (bob) 生成本地的密钥 bobDesKey &lt;br/&gt;    bobKeyAgree.doPhase(alicePubKey, true); &lt;br/&gt;    SecretKey bobDesKey = bobKeyAgree.generateSecret("DES"); &lt;br/&gt;    System.out.println("BOB: 用 alice 的公钥定位本地 key, 生成本地 DES 密钥成功"); &lt;br/&gt;        // Bob 生成公共密钥 bobPubKeyEnc 并发送给 Alice, &lt;br/&gt;        // 比如用文件方式 ,socket....., 使其生成本地密钥&lt;br/&gt;    byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded(); &lt;br/&gt;        System.out.println("BOB 向 ALICE 发送公钥"); &lt;br/&gt;         // alice 接收到 bobPubKeyEnc 后生成 bobPubKey &lt;br/&gt;         // 再进行定位 , 使 aliceKeyAgree 定位在 bobPubKey &lt;br/&gt;    KeyFactory aliceKeyFac = KeyFactory.getInstance("DH"); &lt;br/&gt;    x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc); &lt;br/&gt;    PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec); &lt;br/&gt;       System.out.println("ALICE 接收 BOB 公钥并解码成功"); &lt;br/&gt; ; &lt;br/&gt;    KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH"); &lt;br/&gt;    aliceKeyAgree.init(aliceKpair.getPrivate()); &lt;br/&gt;        System.out.println("ALICE: 初始化本地 key 成功"); &lt;br/&gt;    aliceKeyAgree.doPhase(bobPubKey, true); &lt;br/&gt;        // 张三 (alice) 生成本地的密钥 aliceDesKey &lt;br/&gt;    SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES"); &lt;br/&gt;        System.out.println("ALICE: 用 bob 的公钥定位本地 key, 并生成本地 DES 密钥"); &lt;br/&gt;        if (aliceDesKey.equals(bobDesKey)) System.out.println("张三和李四的密钥相同"); &lt;br/&gt;       // 现在张三和李四的本地的 deskey 是相同的所以 , 完全可以进行发送加密 , 接收后解密 , 达到&lt;br/&gt;       // 安全通道的的目的&lt;br/&gt;        /* &lt;br/&gt;         * bob 用 bobDesKey 密钥加密信息&lt;br/&gt;         */ &lt;br/&gt;    Cipher bobCipher = Cipher.getInstance("DES"); &lt;br/&gt;    bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey); &lt;br/&gt;        String bobinfo= "这是李四的机密信息"; &lt;br/&gt;        System.out.println("李四加密前原文 :"+bobinfo); &lt;br/&gt;    byte[] cleartext =bobinfo.getBytes(); &lt;br/&gt;    byte[] ciphertext = bobCipher.doFinal(cleartext); &lt;br/&gt;        /* &lt;br/&gt;         * alice 用 aliceDesKey 密钥解密&lt;br/&gt;         */ &lt;br/&gt;    Cipher aliceCipher = Cipher.getInstance("DES"); &lt;br/&gt;    aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey); &lt;br/&gt;    byte[] recovered = aliceCipher.doFinal(ciphertext); &lt;br/&gt;        System.out.println("alice 解密 bob 的信息 :"+(new String(recovered))); &lt;br/&gt;    if (!java.util.Arrays.equals(cleartext, recovered)) &lt;br/&gt;        throw new Exception("解密后与原文信息不同"); &lt;br/&gt;    System.out.println("解密后相同"); &lt;br/&gt;    } &lt;br/&gt; }&lt;p&gt;&lt;a href="http://www.ibm.com/developerworks/cn/java/l-security/#ibm-pcon"&gt;回页首&lt;/a&gt; &lt;p&gt;&lt;a name="3"&gt;第 3 章小结&lt;/a&gt; &lt;p&gt;在加密术中生成密钥对时，密钥对的当然是越长越好，但费时也越多，请从中从实际出发选取合适的长度，大部分例码中的密钥是每次运行就从新生成，在实际的情况中是生成后在一段时间保存在文件中，再次运行直接从文件中读入，从而加快速度。当然定时更新和加强密钥保管的安全性也是必须的。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2119959.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/07/28/2119959.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/sgsoft/archive/2011/07/08/2100943.html</id><title type="text">Exploring The Major Interfaces in Rx</title><summary type="text">本文描述了主要的Reactive Extensions (Rx)接口，其用于表示observable序列，并subscribe它们。 IObservable&lt;T&gt;/IObserver&lt;T&gt;在.NET ...</summary><published>2011-07-08T06:09:00Z</published><updated>2011-07-08T06:09:00Z</updated><author><name>海天一鸥</name><uri>http://www.cnblogs.com/sgsoft/</uri></author><link rel="alternate" href="http://www.cnblogs.com/sgsoft/archive/2011/07/08/2100943.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/sgsoft/archive/2011/07/08/2100943.html"/><content type="html">&lt;p&gt;本文描述了主要的Reactive Extensions (Rx)接口，其用于表示observable序列，并subscribe它们。  &lt;p&gt;IObservable&amp;lt;T&amp;gt;/IObserver&amp;lt;T&amp;gt;在.NET 4.0基础类库中出现，它们也可作为.NET 3.5, Silverlight 3 and 4以及Javascript的一个包安装。  &lt;p&gt;&lt;b&gt;IObservable&amp;lt;T&amp;gt;/IObserver&amp;lt;T&amp;gt;&lt;/b&gt;  &lt;p&gt;Rx exposes asynchronous and event-based data sources as push-based, observable sequences abstracted by the new IObservable&amp;lt;T&amp;gt; interface in .NET Framework 4.0. This IObservable&amp;lt;T&amp;gt; interface is a dual of the familiar IEnumerable&amp;lt;T&amp;gt; interface used for pull-based, enumerable collections. It represents a data source that can be observed, meaning that it can send data to anyone who is interested. It maintains a list of dependent IObserver&amp;lt;T&amp;gt; implementations representing such interested listeners, and notifies them automatically of any state changes.  &lt;p&gt;Rx公开异步和基于事件的数据源，作为push模式的基础，observable序列由.NET Framework 4.0中的IObservable&amp;lt;T&amp;gt;接口抽象。IObservable&amp;lt;T&amp;gt;接口非常类似于IEnumerable&amp;lt;T&amp;gt;接口，只是IEnumerable&amp;lt;T&amp;gt;接口用于pull-based，可枚举集合。IObservable&amp;lt;T&amp;gt;接口代表可被观察的数据源——即它可以发送数据给任何关注他的对象。它维护了一个依赖于IObserver&amp;lt;T&amp;gt;实现的对象的列表，诸如那些关注数据源的listeners，并自动通知它们任何状态更改。  &lt;p&gt;An implementation of the IObservable&amp;lt;T&amp;gt; interface can be viewed as a collection of elements of type T. Therefore, an IObservable&amp;lt;int&amp;gt; can be viewed as a collection of integers, in which integers will be pushed to the subscribed observers.  &lt;p&gt;IObservable&amp;lt;T&amp;gt;接口的实现可呈现为元素T的一个集合。因此，IObservable&amp;lt;int&amp;gt;可以视为整数集合，在它里面，整数将被push给每个订阅的observers。  &lt;p&gt;As described in &lt;a href="http://msdn.microsoft.com/en-us/library/hh242962%28v=VS.103%29.aspx"&gt;What is Rx&lt;/a&gt;, the other half of the push model is represented by the IObserver&amp;lt;T&amp;gt; interface, which represents an observer who registers an interest through a subscription. Items are subsequently handed to the observer from the observable sequence to which it subscribes.  &lt;p&gt;如&lt;a href="http://msdn.microsoft.com/en-us/library/hh242962%28v=VS.103%29.aspx"&gt;What is Rx&lt;/a&gt;所述，push模式的另一半由IObserver&amp;lt;T&amp;gt;接口表示，它代表一个observer，其通过subscription注册关注点（interest）。项随后从observable序列被移交给订阅了它的observer。  &lt;p&gt;In order to receive notifications from an observable collection, you use the Subscribe method of IObservable to hand it an IObserver&amp;lt;T&amp;gt; object. In return for this observer, the Subscribe method returns an IDisposable object that acts as a handle for the subscription. This allows you to clean up the subscription after you are done.&amp;nbsp; Calling Dispose on this object detaches the observer from the source so that notifications are no longer delivered. As you can infer, in Rx you do not need to explicitly unsubscribe from an event as in the .NET event model.  &lt;p&gt;为了从observable集合接收到通知，需使用IObservable 接口的Subscribe方法，以将IObservable移交给IObserver&amp;lt;T&amp;gt;对象。此observer的返回中，Subscribe方法返回了一个IDisposable对象，它代表这个subscription的handle。这允许你完成处理后清除subscription。调用此对象上的Dispose方法将分离此observer与源，这样，通知将不再传输给它。如你所推断，在Rx中，你无须像在.NET 事件模型中那样显式的unsubscribe event。  &lt;p&gt;Observers support three publication events, reflected by the interface’s methods. OnNext can be called zero or more times, when the observable data source has data available. For example, an observable data source used for mouse move events can send out a Point object every time the mouse has moved. The other two methods are used to indicate completion or errors.  &lt;p&gt;Observers支持3个公开的事件，都由接口的方法所反映。OnNext可以被调用0次或多次，当observable数据源具有有效数据时。例如，用于mouse move事件的observable数据源可以在每次mouse移动时发送一个Point对象。另2个方法用于指示完成或错误状态。  &lt;p&gt;The following lists the IObservable&amp;lt;T&amp;gt;/IObserver&amp;lt;T&amp;gt; interfaces.  &lt;p&gt;下面是IObservable&amp;lt;T&amp;gt;/IObserver&amp;lt;T&amp;gt;接口定义。&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IObservable&amp;lt;&lt;span class="kwrd"&gt;out&lt;/span&gt; T&amp;gt; &lt;br/&gt;&lt;br/&gt;{ &lt;br/&gt;&lt;br/&gt;IDisposable Subscribe(IObserver&amp;lt;T&amp;gt; observer); &lt;br/&gt;&lt;br/&gt;} &lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IObserver&amp;lt;&lt;span class="kwrd"&gt;in&lt;/span&gt; T&amp;gt; &lt;br/&gt;&lt;br/&gt;{ &lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; OnCompleted(); &lt;span class="rem"&gt;// Notifies the observer that the source has finished sending messages.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; OnError(Exception error); &lt;span class="rem"&gt;// Notifies the observer about any exception or error.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; OnNext(T &lt;span class="kwrd"&gt;value&lt;/span&gt;); &lt;span class="rem"&gt;// Pushes the next data value from the source to the observer.&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;} &lt;br/&gt;&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;a name="CodeSpippet0"&gt;&lt;/a&gt;Rx also provides Subscribe extension methods so that you can avoid implementing the IObserver&amp;lt;T&amp;gt; interface yourself. For each publication event (OnNext, OnError, OnCompleted) of an observable sequence, you can specify a delegate that will be invoked, as shown in the following example. If you do not specify an action for an event, the default behavior will occur. &lt;p&gt;Rx也提供了Subscribe扩展方法，因此你可以避免自己去实现IObserver&amp;lt;T&amp;gt;接口。对于observable序列的每个公开事件（OnNext, OnError, OnCompleted），你可以指定一个委托，其再合适的时候被调用，如下例所示。如果你没有为事件指定一个action，默认的行为将发生。IObservable&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; source = Observable.Range(1, 5); &lt;span class="rem"&gt;//creates an observable sequence of 5 integers, starting from 1&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;IDisposable subscription = source.Subscribe(&lt;br/&gt;&lt;br/&gt;x =&amp;gt; Console.WriteLine(&lt;span class="str"&gt;"OnNext: {0}"&lt;/span&gt;, x), &lt;span class="rem"&gt;//prints out the value being pushed&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;ex =&amp;gt; Console.WriteLine(&lt;span class="str"&gt;"OnError: {0}"&lt;/span&gt;, ex.Message),&lt;br/&gt;&lt;br/&gt;() =&amp;gt; Console.WriteLine(&lt;span class="str"&gt;"OnCompleted"&lt;/span&gt;));&lt;br/&gt;&lt;br/&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;You can treat the observable sequence (such as a sequence of mouse-over events) as if it were a normal collection. Thus you can write LINQ queries over the collection to do things like filtering, grouping, composing, etc. To make observable sequences more useful, the Rx assemblies provide many factory LINQ operators so that you do not need to implement any of these on your own. This will be covered in the &lt;a href="http://msdn.microsoft.com/en-us/library/hh242983%28v=VS.103%29.aspx"&gt;Querying Observable Sequences using LINQ Operators&lt;/a&gt; topic. &lt;p&gt;你可以像普通集合那样对待observable sequence（如：mouse over事件序列）。因此你可以在这个集合上编写编写LINQ查询，执行诸如过滤，分组，组合等等。为了使observable sequences更有用，Rx程序集提供了很多工厂LINQ操作，请参考&lt;a href="http://msdn.microsoft.com/en-us/library/hh242983%28v=VS.103%29.aspx"&gt;Querying Observable Sequences using LINQ Operators&lt;/a&gt;。 &lt;table border="0" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107081409205010.gif"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image001" border="0" alt="clip_image001" src="http://images.cnblogs.com/cnblogs_com/sgsoft/201107/201107081409216863.gif" width="10" height="10"&gt;&lt;/a&gt;&lt;/b&gt;&lt;b&gt;Caution: &lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;You do not need to implement the IObservable&amp;lt;T&amp;gt;/IObserver&amp;lt;T&amp;gt; interfaces yourself.&amp;nbsp; Rx provides internal implementations of these interfaces for you and exposes them through various extension methods provided by the &lt;a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable%28v=VS.103%29.aspx"&gt;Observable&lt;/a&gt; and Observer types.&amp;nbsp; See the &lt;a href="http://msdn.microsoft.com/en-us/library/hh242972%28v=VS.103%29.aspx"&gt;Creating and Querying Observable Sequences&lt;/a&gt; topic for more information.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;注意：你无须自行实现IObservable&amp;lt;T&amp;gt;/IObserver&amp;lt;T&amp;gt;接口。Rx提供了这些接口的internal实现，并通过&lt;a href="http://msdn.microsoft.com/en-us/library/system.reactive.linq.observable%28v=VS.103%29.aspx"&gt;Observable&lt;/a&gt; and Observer类型的各种扩展方法公开它们，参考&lt;a href="http://msdn.microsoft.com/en-us/library/hh242972%28v=VS.103%29.aspx"&gt;Creating and Querying Observable Sequences&lt;/a&gt;。 &lt;img src="http://www.cnblogs.com/sgsoft/aggbug/2100943.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/sgsoft/archive/2011/07/08/2100943.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
