<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Zongsoft Corporation</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/10622/rss</id><updated>2011-08-27T10:35:17Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/10622/rss"/><entry><id>http://www.cnblogs.com/SW515/archive/2011/08/27/2155691.html</id><title type="text">ASP.NET MVC 3.0 源码阅读手记(1)</title><summary type="text">前言：本文或许不太适合大众阅读，这只是本人查看ASP.NET MVC 3.0源码时记的流水账，文中夹杂诸多未经证实的猜想，请自行采纳。文中亦摘录了很多代码，主要是为了方便以后阅读时懒得再翻看对照源码，特此声明。 在阅读源码前先了解下MVC的大致处理流程还是很有必要的，网上比较出名的是Steven Sanderson提供的一份请求处理流程图(原文：请猛击这里)。 因为在使用ASP.NET...</summary><published>2011-08-27T10:03:00Z</published><updated>2011-08-27T10:03:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2011/08/27/2155691.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2011/08/27/2155691.html"/><content type="html">&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&#xD;
&lt;/style&gt;  &lt;div style="font-size: 11pt"&gt; &lt;p style="text-indent: 2em"&gt;前言：本文或许不太适合大众阅读，这只是本人查看ASP.NET MVC 3.0源码时记的流水账，文中夹杂诸多未经证实的猜想，请自行采纳。文中亦摘录了很多代码，主要是为了方便以后阅读时懒得再翻看对照源码，特此声明。 &lt;/p&gt; &lt;p style="text-indent: 2em"&gt;在阅读源码前先了解下MVC的大致处理流程还是很有必要的，网上比较出名的是&lt;a href="http://blog.stevensanderson.com" target="_blank"&gt;Steven Sanderson&lt;/a&gt;提供的一份请求处理流程图(原文：&lt;a href="http://blog.stevensanderson.com/2009/10/08/aspnet-mvc-learning-resource-request-handling-pipeline-poster/" target="_blank"&gt;请猛击这里&lt;/a&gt;)。 &lt;/p&gt; &lt;p style="text-align: center"&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/SW515/201108/201108271802456905.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="asp_net_mvc_Pipeline" border="0" alt="asp_net_mvc_Pipeline" align="center" src="http://images.cnblogs.com/cnblogs_com/SW515/201108/201108271802461441.png" width="190" height="244"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style="text-indent: 2em"&gt;因为在使用ASP.NET MVC开发的时候，我们首先接触到的是路由，亦传说中的 &lt;font color="#0000ff" face="Courier New"&gt;System.Web.Routing.RouteTable&lt;/font&gt;，Reflection该类的代码如下：&lt;/p&gt; &lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;br&gt;&lt;span &gt;private&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteCollection&lt;/font&gt; _instance = &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteCollection&lt;/font&gt;();&#xD;
&#xD;
&lt;span &gt;public&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteCollection&lt;/font&gt; Routes&#xD;
{&#xD;
    [&lt;font color="#c0504d"&gt;TargetedPatchingOptOut&lt;/font&gt;(&lt;span &gt;"Performance critical to inline this type of method across NGen image boundaries"&lt;/span&gt;)]&#xD;
    &lt;font color="#0000ff"&gt;get&lt;/font&gt;&#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; RouteTable._instance;&#xD;
    }&#xD;
}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;好吧，这么的单纯简单，那就去看看RouteCollection的代码吧，发现该类中并无常用的那个&lt;font color="#0000ff" face="Courier New"&gt;MapRoute&lt;/font&gt;方法，原来该方法是MVC框架扩展的，具体代码位于MVC项目源码中的 &lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;System.Web.Mvc.RouteCollectionExtensions&lt;/font&gt; &lt;/font&gt;类，下面是其代码：&lt;/p&gt;&#xD;
&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; Route MapRoute(&lt;span &gt;this&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteCollection&lt;/font&gt; routes, &lt;span &gt;string&lt;/span&gt; name, &lt;span &gt;string&lt;/span&gt; url, &lt;span &gt;object&lt;/span&gt; defaults, &lt;span &gt;object&lt;/span&gt; constraints, &lt;span &gt;string&lt;/span&gt;[] namespaces)&lt;/pre&gt;&lt;pre &gt;{&#xD;
        &lt;span &gt;if&lt;/span&gt; (routes == &lt;span &gt;null&lt;/span&gt;) {&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;ArgumentNullException&lt;/font&gt;(&lt;span &gt;"routes"&lt;/span&gt;);&#xD;
        }&#xD;
        &lt;span &gt;if&lt;/span&gt; (url == &lt;span &gt;null&lt;/span&gt;) {&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;ArgumentNullException&lt;/font&gt;(&lt;span &gt;"url"&lt;/span&gt;);&#xD;
        }&#xD;
&#xD;
        &lt;font color="#c0504d"&gt;Route&lt;/font&gt; route = &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;Route&lt;/font&gt;(url, &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;MvcRouteHandler&lt;/font&gt;()) {&#xD;
            Defaults = &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteValueDictionary&lt;/font&gt;(defaults),&#xD;
            Constraints = &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteValueDictionary&lt;/font&gt;(constraints),&#xD;
            DataTokens = &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;RouteValueDictionary&lt;/font&gt;()&#xD;
        };&#xD;
&#xD;
        &lt;span &gt;if&lt;/span&gt; ((namespaces != &lt;span &gt;null&lt;/span&gt;) &amp;amp;&amp;amp; (namespaces.Length &amp;gt; 0)) {&#xD;
            route.DataTokens[&lt;span &gt;"Namespaces"&lt;/span&gt;] = namespaces;&#xD;
        }&#xD;
&#xD;
        routes.Add(name, route);&#xD;
&#xD;
        &lt;span &gt;return&lt;/span&gt; route;&#xD;
    }&#xD;
&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;以上代码虽简单但有两处重点：&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;创建了一个Route对象，在其构造函数中传入了MvcRouteHandler对象； &#xD;
&lt;li&gt;设置了新建Route对象的Default、Constraints、DataTokens这三个RouteValueDictionary类型的属性，其中默认值(Defaults)和约束(Constraints)是通过object的对象进行初始化的，关于RouteValueDictionary类型是以string为键object为值的字典，具体代码这里就不贴了，大家可以反射看看。 &lt;/li&gt;&lt;/ol&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;我们只要看看RouteValueDictionary这个构造函数以及私有的AddValues方法即可：&lt;/p&gt;&#xD;
&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;span &gt;public&lt;/span&gt; RouteValueDictionary(&lt;span &gt;object&lt;/span&gt; values)&#xD;
{&#xD;
    &lt;span &gt;this&lt;/span&gt;._dictionary = &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;Dictionary&lt;/font&gt;&amp;lt;&lt;span &gt;string&lt;/span&gt;, &lt;span &gt;object&lt;/span&gt;&amp;gt;(&lt;font color="#4bacc6"&gt;StringComparer.OrdinalIgnoreCase&lt;/font&gt;);&#xD;
    &lt;span &gt;this&lt;/span&gt;.AddValues(values);&#xD;
}&lt;/pre&gt;&lt;pre &gt;&lt;span &gt;private&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; AddValues(&lt;span &gt;object&lt;/span&gt; values)&#xD;
{&#xD;
    &lt;span &gt;if&lt;/span&gt; (values != &lt;span &gt;null&lt;/span&gt;)&#xD;
    {&#xD;
        &lt;font color="#c0504d"&gt;PropertyDescriptorCollection&lt;/font&gt; properties = &lt;font color="#c0504d"&gt;TypeDescriptor&lt;/font&gt;.GetProperties(values);&#xD;
        &lt;span &gt;foreach&lt;/span&gt; (&lt;font color="#c0504d"&gt;PropertyDescriptor&lt;/font&gt; propertyDescriptor &lt;span &gt;in&lt;/span&gt; properties)&#xD;
        {&#xD;
            &lt;span &gt;object&lt;/span&gt; &lt;span &gt;value&lt;/span&gt; = propertyDescriptor.GetValue(values);&#xD;
            &lt;span &gt;this&lt;/span&gt;.Add(propertyDescriptor.Name, &lt;span &gt;value&lt;/span&gt;);&#xD;
        }&#xD;
    }&#xD;
}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;上面的AddValues方法利用了TypeDescriptor来获取values参数指定的任意对象的公共属性集，并将这些属性值以名称/值的方式加入到内部字典中，这对于使用匿名类进行设置Route对象中的相关属性非常方便。在MapRoute方法中，使用的是MvcRouteHandler的默认构造函数来创建它的实例，那么就顺藤摸瓜吧：&lt;/p&gt;&#xD;
&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; &lt;font color="#c0504d"&gt;MvcRouteHandler&lt;/font&gt; : &lt;font color="#c0504d"&gt;IRouteHandler&lt;/font&gt; {&#xD;
    &lt;span &gt;private&lt;/span&gt; &lt;font color="#c0504d"&gt;IControllerFactory&lt;/font&gt; _controllerFactory;&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; MvcRouteHandler() {&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; MvcRouteHandler(&lt;font color="#c0504d"&gt;IControllerFactory&lt;/font&gt; controllerFactory) {&#xD;
        _controllerFactory = controllerFactory;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;protected&lt;/span&gt; &lt;span &gt;virtual&lt;/span&gt; &lt;font color="#c0504d"&gt;IHttpHandler&lt;/font&gt; GetHttpHandler(&lt;font color="#c0504d"&gt;RequestContext&lt;/font&gt; requestContext) {&#xD;
        requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));&#xD;
         &lt;span &gt;return&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;MvcHandler&lt;/font&gt;(requestContext);&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;protected&lt;/span&gt; &lt;span &gt;virtual&lt;/span&gt; &lt;font color="#c0504d"&gt;SessionStateBehavior&lt;/font&gt; GetSessionStateBehavior(&lt;font color="#c0504d"&gt;RequestContext&lt;/font&gt; requestContext) {&#xD;
        &lt;span &gt;string&lt;/span&gt; controllerName = (&lt;span &gt;string&lt;/span&gt;)requestContext.RouteData.Values[&lt;span &gt;"controller"&lt;/span&gt;];&#xD;
        &lt;font color="#c0504d"&gt;IControllerFactory&lt;/font&gt; controllerFactory = _controllerFactory ?? &lt;font color="#c0504d"&gt;ControllerBuilder&lt;/font&gt;.Current.GetControllerFactory();&#xD;
        &lt;span &gt;return&lt;/span&gt; controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;&lt;font color="#0000ff"&gt;&lt;font color="#000000"&gt;#&lt;/font&gt;region&lt;/font&gt;&lt;/span&gt; &lt;font color="#a5a5a5"&gt;IRouteHandler Members&lt;/font&gt;&#xD;
    &lt;font color="#c0504d"&gt;IHttpHandler&lt;/font&gt; &lt;font color="#c0504d"&gt;IRouteHandler&lt;/font&gt;.GetHttpHandler(&lt;font color="#c0504d"&gt;RequestContext&lt;/font&gt; requestContext) {&#xD;
        &lt;span &gt;return&lt;/span&gt; GetHttpHandler(requestContext);&#xD;
    }&#xD;
    &lt;span &gt;&lt;font color="#000000"&gt;#&lt;/font&gt;&lt;font color="#0000ff"&gt;endregion&lt;/font&gt;&lt;/span&gt;&#xD;
}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;在GetHttpHandler方法最后返回了一个新建的MvcHandler对象，这个类先按着不表。先看看关于控制器工厂的问题，由于默认构造函数保留了_controllerFactory成员变量为空(null)，因此GetSessionStateBehavior方法中是通过ControllerBuilder来获取控制器工厂对象的，且看看它是如何获取的：&lt;/p&gt;&#xD;
&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; ControllerBuilder&#xD;
{&#xD;
    &lt;span &gt;private&lt;/span&gt; Func&amp;lt;IControllerFactory&amp;gt; _factoryThunk = () =&amp;gt; &lt;span &gt;null&lt;/span&gt;;&#xD;
    &lt;span &gt;private&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; ControllerBuilder _instance = &lt;span &gt;new&lt;/span&gt; ControllerBuilder();&#xD;
    &lt;span &gt;private&lt;/span&gt; HashSet&amp;lt;&lt;span &gt;string&lt;/span&gt;&amp;gt; _namespaces = &lt;span &gt;new&lt;/span&gt; HashSet&amp;lt;&lt;span &gt;string&lt;/span&gt;&amp;gt;(StringComparer.OrdinalIgnoreCase);&#xD;
    &lt;span &gt;private&lt;/span&gt; IResolver&amp;lt;IControllerFactory&amp;gt; _serviceResolver;&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; ControllerBuilder() : &lt;span &gt;this&lt;/span&gt;(&lt;span &gt;null&lt;/span&gt;)&#xD;
    {&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;internal&lt;/span&gt; ControllerBuilder(IResolver&amp;lt;IControllerFactory&amp;gt; serviceResolver)&#xD;
    {&#xD;
        _serviceResolver = serviceResolver ?? &lt;span &gt;new&lt;/span&gt; SingleServiceResolver&amp;lt;IControllerFactory&amp;gt;(&#xD;
            () =&amp;gt; _factoryThunk(),&#xD;
             &lt;span &gt;new&lt;/span&gt; DefaultControllerFactory&#xD;
             {&#xD;
                 ControllerBuilder = &lt;span &gt;this&lt;/span&gt;&#xD;
             },&#xD;
            &lt;span &gt;"ControllerBuilder.GetControllerFactory"&lt;/span&gt;&#xD;
        );&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; ControllerBuilder Current&#xD;
    {&#xD;
        get&#xD;
        {&#xD;
            &lt;span &gt;return&lt;/span&gt; _instance;&#xD;
        }&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; HashSet&amp;lt;&lt;span &gt;string&lt;/span&gt;&amp;gt; DefaultNamespaces&#xD;
    {&#xD;
        get&#xD;
        {&#xD;
            &lt;span &gt;return&lt;/span&gt; _namespaces;&#xD;
        }&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; IControllerFactory GetControllerFactory()&#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; _serviceResolver.Current;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; SetControllerFactory(IControllerFactory controllerFactory)&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(controllerFactory == &lt;span &gt;null&lt;/span&gt;)&#xD;
        {&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"controllerFactory"&lt;/span&gt;);&#xD;
        }&#xD;
&#xD;
        _factoryThunk = () =&amp;gt; controllerFactory;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; SetControllerFactory(Type controllerFactoryType)&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(controllerFactoryType == &lt;span &gt;null&lt;/span&gt;)&#xD;
        {&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"controllerFactoryType"&lt;/span&gt;);&#xD;
        }&#xD;
        &lt;span &gt;if&lt;/span&gt;(!&lt;span &gt;typeof&lt;/span&gt;(IControllerFactory).IsAssignableFrom(controllerFactoryType))&#xD;
        {&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentException(&#xD;
                String.Format(&#xD;
                    CultureInfo.CurrentCulture,&#xD;
                    MvcResources.ControllerBuilder_MissingIControllerFactory,&#xD;
                    controllerFactoryType),&#xD;
                &lt;span &gt;"controllerFactoryType"&lt;/span&gt;);&#xD;
        }&#xD;
&#xD;
        _factoryThunk = &lt;span &gt;delegate&lt;/span&gt;()&#xD;
        {&#xD;
            &lt;span &gt;try&lt;/span&gt;&#xD;
            {&#xD;
                &lt;span &gt;return&lt;/span&gt; (IControllerFactory)Activator.CreateInstance(controllerFactoryType);&#xD;
            }&#xD;
            &lt;span &gt;catch&lt;/span&gt;(Exception ex)&#xD;
            {&#xD;
                &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; InvalidOperationException(&#xD;
                    String.Format(&#xD;
                        CultureInfo.CurrentCulture,&#xD;
                        MvcResources.ControllerBuilder_ErrorCreatingControllerFactory,&#xD;
                        controllerFactoryType),&#xD;
                    ex);&#xD;
            }&#xD;
        };&#xD;
    }&#xD;
}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;大致看看，这个类主要就是用来获取IControllerFactory对象的，其中GetControllerFactory方法很简单，通过内部的IResolver&amp;lt;IControllerFactory&amp;gt;来解析得到想要的IControllerFactory服务，其中两个重载的SetControllerFactory注入方法的实现比较简单，只是刚开始有点奇怪为什么不直接通过将注入的IControllerFactory类型的controllerFactory参数保存起来作为GetControllerFactory的返回之用，还非得绕个弯弯通过_factoryThunk 这个委托进行返回？没事，看到后面就知道为什么了，据说这也是MVC 3.0中为了扩展性加入的新处理方式(至于听谁说的…)。既然ControllerBuilder把获取IControllerFactory的职责都交给了默认的SingleServiceResolver类，那么就看看它是咋么一回事吧！&lt;/p&gt;&#xD;
&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;span &gt;internal&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; SingleServiceResolver&amp;lt;TService&amp;gt; : IResolver&amp;lt;TService&amp;gt; &lt;span &gt;where&lt;/span&gt; TService : &lt;span &gt;class&lt;/span&gt;&#xD;
{&#xD;
    &lt;span &gt;private&lt;/span&gt; TService _currentValueFromResolver;&#xD;
    &lt;span &gt;private&lt;/span&gt; Func&amp;lt;TService&amp;gt; _currentValueThunk;&#xD;
    &lt;span &gt;private&lt;/span&gt; TService _defaultValue;&#xD;
    &lt;span &gt;private&lt;/span&gt; Func&amp;lt;IDependencyResolver&amp;gt; _resolverThunk;&#xD;
    &lt;span &gt;private&lt;/span&gt; &lt;span &gt;string&lt;/span&gt; _callerMethodName;&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; SingleServiceResolver(Func&amp;lt;TService&amp;gt; currentValueThunk, TService defaultValue, &lt;span &gt;string&lt;/span&gt; callerMethodName)&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(currentValueThunk == &lt;span &gt;null&lt;/span&gt;)&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"currentValueThunk"&lt;/span&gt;);&#xD;
&#xD;
        &lt;span &gt;if&lt;/span&gt;(defaultValue == &lt;span &gt;null&lt;/span&gt;)&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"defaultValue"&lt;/span&gt;);&#xD;
&#xD;
        _resolverThunk = () =&amp;gt; DependencyResolver.Current;&#xD;
        _currentValueThunk = currentValueThunk;&#xD;
        _defaultValue = defaultValue;&#xD;
        _callerMethodName = callerMethodName;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; TService Current&#xD;
    {&#xD;
        get&#xD;
        {&#xD;
            &lt;span &gt;if&lt;/span&gt;(_resolverThunk != &lt;span &gt;null&lt;/span&gt;)&#xD;
            {&#xD;
                &lt;span &gt;lock&lt;/span&gt;(_currentValueThunk)&#xD;
                {&#xD;
                    &lt;span &gt;if&lt;/span&gt;(_resolverThunk != &lt;span &gt;null&lt;/span&gt;)&#xD;
                    {&#xD;
                        _currentValueFromResolver = _resolverThunk().GetService&amp;lt;TService&amp;gt;();&#xD;
                        _resolverThunk = &lt;span &gt;null&lt;/span&gt;;&#xD;
&#xD;
                        &lt;span &gt;if&lt;/span&gt;(_currentValueFromResolver != &lt;span &gt;null&lt;/span&gt; &amp;amp;&amp;amp; _currentValueThunk() != &lt;span &gt;null&lt;/span&gt;)&#xD;
                        {&#xD;
                            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.SingleServiceResolver_CannotRegisterTwoInstances, &lt;span &gt;typeof&lt;/span&gt;(TService).Name.ToString(), _callerMethodName));&#xD;
                        }&#xD;
                    }&#xD;
                }&#xD;
            }&#xD;
&#xD;
            &lt;span &gt;return&lt;/span&gt; _currentValueFromResolver ?? _currentValueThunk() ?? _defaultValue;&#xD;
        }&#xD;
    }&#xD;
}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;在SingleServiceResolver类的Current属性中，首先是判断_resolverThunk成员变量是否为空，而这个变量是返回IDependencyResolver接口的一个委托，在构造函数中可以看到它指向DependencyResolver类的静态属性Current(这个东东先且放放)，紧接着就是标准的双检锁的处理，具体工作代码是通过这个委托获取到的IDependcencyResolver的GetService方法来获取IControllerFactory，获取到之后马上将该委托置空，然后判断获取到的控制器工厂对象是否不为空并且通过构造函数传入的那个“绕弯弯”的返回IControllerFactory的委托返回的控制器工厂是否也不为空，如果都不为空则表示获取方式有冲突，变抛出一个无效操作异常，该异常表示不能注册两种获取服务实例的方式。 &#xD;
&lt;p&gt;&lt;p style="text-indent: 2em"&gt;最后一行是返回代码，这里有蹊跷，它表明了对几种获取服务方式的优先级：&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;优先使用IDependencyResolver的GetService方法的结果； &#xD;
&lt;li&gt;其次使用构造函数传入的Func&amp;lt;IControllerFactory&amp;gt;类型参数的委托返回结果； &#xD;
&lt;li&gt;最后才使用构造函数传入的具体的IControllerFactory类型的控制器工厂对象。 &lt;/li&gt;&lt;/ol&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;看到这里，是不是有些眼熟？貌似跟很多IoC框架中的那个ServiceLocator有点神似呢？不扯这个了，既然弄清楚了优先级别，那么根据构造函数的代码，这个优先级别最高的依赖解析器(IDependencyResolver)指向了DependencyResolver的Current静态属性，那么就去围观下它吧：&lt;/p&gt;&#xD;
&lt;div style="border-bottom: gray 1px solid; border-left: gray 1px solid; padding-bottom: 0.5em; padding-left: 0.5em; padding-right: 0.5em; border-top: gray 1px solid; border-right: gray 1px solid; padding-top: 0.5em"&gt;&lt;pre &gt;&lt;span &gt;public&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; DependencyResolver&#xD;
{&#xD;
    &lt;span &gt;private&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; DependencyResolver _instance = &lt;span &gt;new&lt;/span&gt; DependencyResolver();&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; IDependencyResolver Current&#xD;
    {&#xD;
        get&#xD;
        {&#xD;
            &lt;span &gt;return&lt;/span&gt; _instance.InnerCurrent;&#xD;
        }&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;private&lt;/span&gt; IDependencyResolver _current = &lt;span &gt;new&lt;/span&gt; DefaultDependencyResolver();&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; IDependencyResolver InnerCurrent&#xD;
    {&#xD;
        get&#xD;
        {&#xD;
            &lt;span &gt;return&lt;/span&gt; _current;&#xD;
        }&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; InnerSetResolver(IDependencyResolver resolver)&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(resolver == &lt;span &gt;null&lt;/span&gt;)&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"resolver"&lt;/span&gt;);&#xD;
&#xD;
        _current = resolver;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; InnerSetResolver(&lt;span &gt;object&lt;/span&gt; commonServiceLocator)&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(commonServiceLocator == &lt;span &gt;null&lt;/span&gt;)&#xD;
                &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"commonServiceLocator"&lt;/span&gt;);&#xD;
&#xD;
        Type locatorType = commonServiceLocator.GetType();&#xD;
        MethodInfo getInstance = locatorType.GetMethod(&lt;span &gt;"GetInstance"&lt;/span&gt;, &lt;span &gt;new&lt;/span&gt;[] { &lt;span &gt;typeof&lt;/span&gt;(Type) });&#xD;
        MethodInfo getInstances = locatorType.GetMethod(&lt;span &gt;"GetAllInstances"&lt;/span&gt;, &lt;span &gt;new&lt;/span&gt;[] { &lt;span &gt;typeof&lt;/span&gt;(Type) });&#xD;
&#xD;
        &lt;span &gt;if&lt;/span&gt;(getInstance == &lt;span &gt;null&lt;/span&gt; ||&#xD;
            getInstance.ReturnType != &lt;span &gt;typeof&lt;/span&gt;(&lt;span &gt;object&lt;/span&gt;) ||&#xD;
            getInstances == &lt;span &gt;null&lt;/span&gt; ||&#xD;
            getInstances.ReturnType != &lt;span &gt;typeof&lt;/span&gt;(IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;))&#xD;
        {&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentException(&#xD;
                String.Format(&#xD;
                    CultureInfo.CurrentCulture,&#xD;
                    MvcResources.DependencyResolver_DoesNotImplementICommonServiceLocator,&#xD;
                    locatorType.FullName&#xD;
                ),&#xD;
                &lt;span &gt;"commonServiceLocator"&lt;/span&gt;&#xD;
            );&#xD;
        }&#xD;
&#xD;
        var getService = (Func&amp;lt;Type, &lt;span &gt;object&lt;/span&gt;&amp;gt;)Delegate.CreateDelegate(&lt;span &gt;typeof&lt;/span&gt;(Func&amp;lt;Type, &lt;span &gt;object&lt;/span&gt;&amp;gt;), commonServiceLocator, getInstance);&#xD;
        var getServices = (Func&amp;lt;Type, IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;&amp;gt;)Delegate.CreateDelegate(&lt;span &gt;typeof&lt;/span&gt;(Func&amp;lt;Type, IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;&amp;gt;), commonServiceLocator, getInstances);&#xD;
&#xD;
        _current = &lt;span &gt;new&lt;/span&gt; DelegateBasedDependencyResolver(getService, getServices);&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; InnerSetResolver(Func&amp;lt;Type, &lt;span &gt;object&lt;/span&gt;&amp;gt; getService, Func&amp;lt;Type, IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;&amp;gt; getServices)&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(getService == &lt;span &gt;null&lt;/span&gt;)&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"getService"&lt;/span&gt;);&#xD;
&#xD;
        &lt;span &gt;if&lt;/span&gt;(getServices == &lt;span &gt;null&lt;/span&gt;)&#xD;
            &lt;span &gt;throw&lt;/span&gt; &lt;span &gt;new&lt;/span&gt; ArgumentNullException(&lt;span &gt;"getServices"&lt;/span&gt;);&#xD;
&#xD;
        _current = &lt;span &gt;new&lt;/span&gt; DelegateBasedDependencyResolver(getService, getServices);&#xD;
    }&#xD;
&#xD;
&lt;hr&gt;&#xD;
&#xD;
    &lt;span &gt;private&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; DelegateBasedDependencyResolver : IDependencyResolver&#xD;
    {&#xD;
        Func&amp;lt;Type, &lt;span &gt;object&lt;/span&gt;&amp;gt; _getService;&#xD;
        Func&amp;lt;Type, IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;&amp;gt; _getServices;&#xD;
&#xD;
        &lt;span &gt;public&lt;/span&gt; DelegateBasedDependencyResolver(Func&amp;lt;Type, &lt;span &gt;object&lt;/span&gt;&amp;gt; getService, Func&amp;lt;Type, IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;&amp;gt; getServices)&#xD;
        {&#xD;
            _getService = getService;&#xD;
            _getServices = getServices;&#xD;
        }&#xD;
&#xD;
        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;object&lt;/span&gt; GetService(Type type)&#xD;
        {&#xD;
            &lt;span &gt;try&lt;/span&gt;&#xD;
            {&#xD;
                &lt;span &gt;return&lt;/span&gt; _getService.Invoke(type);&#xD;
            }&#xD;
            &lt;span &gt;catch&lt;/span&gt;&#xD;
            {&#xD;
                &lt;span &gt;return&lt;/span&gt; &lt;span &gt;null&lt;/span&gt;;&#xD;
            }&#xD;
        }&#xD;
&#xD;
        &lt;span &gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt; GetServices(Type type)&#xD;
        {&#xD;
            &lt;span &gt;return&lt;/span&gt; _getServices(type);&#xD;
        }&#xD;
    }&#xD;
&#xD;
&lt;hr&gt;&#xD;
&#xD;
    &lt;span &gt;private&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; DefaultDependencyResolver : IDependencyResolver&#xD;
    {&#xD;
        &lt;span &gt;public&lt;/span&gt; &lt;span &gt;object&lt;/span&gt; GetService(Type serviceType)&#xD;
        {&#xD;
            &lt;span &gt;try&lt;/span&gt;&#xD;
            {&#xD;
                &lt;span &gt;return&lt;/span&gt; Activator.CreateInstance(serviceType);&#xD;
            }&#xD;
            &lt;span &gt;catch&lt;/span&gt;&#xD;
            {&#xD;
                &lt;span &gt;return&lt;/span&gt; &lt;span &gt;null&lt;/span&gt;;&#xD;
            }&#xD;
        }&#xD;
&#xD;
        &lt;span &gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt; GetServices(Type serviceType)&#xD;
        {&#xD;
            &lt;span &gt;return&lt;/span&gt; Enumerable.Empty&amp;lt;&lt;span &gt;object&lt;/span&gt;&amp;gt;();&#xD;
        }&#xD;
    }&#xD;
}&lt;/pre&gt;&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;这个类的代码个人感觉写得有点矬，有几个简单的静态注册服务的方法就没贴上来了。这个类完全可以写成静态类，属于IDependencyResolver的Facade，其中InnerCurrent属性为获取IDependencyResolver服务，而其他三个InnerSetResolver重载方法分别为不同的注册服务方法，其中第一个很简单，第二个为Common Service Locator模式的注册，第三个以委托的方式进行动态注册。里面两个嵌套类都很容易看懂就不做说明。需要留意的是，当前默认解析器为DefaultDependencyResolver对象，而该对象只是简单的根据服务类型进行反射创建而已。综合上面几个类的代码，跟踪至此我们可以确定，在默认情况下只是由DefaultDependencyResolver类的GetService方法发射创建了制定类型的实例而已。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;且慢，在SingleServiceResolver类的Current属性的getter中，有这行代码：_currentValueFromResolver = _resolverThunk().GetService&amp;lt;TService&amp;gt;();而这个TService泛型参数由ControllerBuilder类的构造函数中指定，且看：_serviceResolver = serviceResolver ?? &lt;span &gt;new&lt;/span&gt; SingleServiceResolver&amp;lt;IControllerFactory&amp;gt;(...); 即 TService 为 IControllerFactory，这样自然由_resolverThunk委托返回的DefaultDependencyResolver对象的GetService(Type serviceType)方法是不能正常工作的，故而被里面的catch捕获而返回空。注意上面的GetService&amp;lt;TService&amp;gt;()泛型方法其实由DependencyResolverExtensions类中定义的扩展方法，但是该扩展方法只是简单调用同名非泛型的原方法而已，故此不做展开。由此回溯，最后还是返回由ControllerBuilder构造函数中所指定的那个控制器工厂对象，即DefaultControllerFactory类实例。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em"&gt;好了，绕了这么一大圈子，结论就是在MVC 3中如果不进行服务替换，默认的控制器工厂就是这个的System.Web.Mvc.DefaultControllerFactory类。虽然这里白绕了一圈，但是也算基本弄明白了它的扩展机制，因为在其他地方都有用到IResolver&amp;lt;T&amp;gt;和IDependencyResolver的。好吧，先看到这…&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/2155691.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2011/08/27/2155691.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2011/07/06/2099505.html</id><title type="text">Mono on Linux 开发与实践札记(1)</title><summary type="text">最近有个政府项目，客户指定服务器程序必须跑在Linux上面，于是乎我们这帮Linux菜鸟立马开装Linux系统并部署Mono环境。因为对Linux实在不熟的缘故，故在RedHat Enterprise Linux 6中始终没有将MonoDevelop跑起来，于是团队中有同事提议“干脆转Java平台算哒”，哎呦，这么“反动”的想法必须得镇压在萌芽状态。好吧，我承认有些许的个人主观因素作祟，但终究还是...</summary><published>2011-07-06T11:43:00Z</published><updated>2011-07-06T11:43:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2011/07/06/2099505.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2011/07/06/2099505.html"/><content type="html">&lt;div style="font-size: 11pt;"&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;最近有个政府项目，客户指定服务器程序必须跑在Linux上面，于是乎我们这帮Linux菜鸟立马开装Linux系统并部署Mono环境。因为对Linux实在不熟的缘故，故在RedHat Enterprise Linux 6中始终没有将MonoDevelop跑起来，于是团队中有同事提议&amp;ldquo;干脆转Java平台算哒&amp;rdquo;，哎呦，这么&amp;ldquo;反动&amp;rdquo;的想法必须得镇压在萌芽状态。好吧，我承认有些许的个人主观因素作祟，但终究还是需要些冠冕堂皇理由的：&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;因为公司现有所有产品都是基于.NET平台，绝大数开发人员也只有.NET开发经验，这样的平台迁移是个非常大成本的事件，而且涉及公司的整个软件开发的方向性转移，绝不可贸然行事。&lt;/li&gt;&#xD;
&lt;li&gt;我一直主张将所有产品统一开发平台，最终将各条产品线全部基于自己研发的插件框架，如果并行Java和.NET两个开发平台，其中涉及的开发量和代码移植、版本同步、双向兼容&amp;hellip;&amp;hellip;想想就是一个浩大而繁琐的工程，这样的焦油坑一定要避免陷入进去。&lt;/li&gt;&#xD;
&lt;li&gt;目前的问题其实只是团队对Mono on Linux的经验匮乏，这个问题还不至于严重到需要迁移开发平台，起码我们还有Mono这样一根救命稻草。所以，我们要做的只是尽快熟悉Linux和积累Mono on Linux上面的一些移植经验，当然，我知道把C#代码移植过去通过Mono的编译并不难，问题在于有些API的细节差异和某些代码契约需要通过一定时间的经验来规避某些小陷阱，但是，这些都是可以解决的。&lt;/li&gt;&#xD;
&lt;li&gt;Mono现在最新稳定版本是2.10.2，对C# 4.0已经支持的很完整了。而且后面很快会有ASP.NET MVC3的完整实现，虽然没有看到对ADO.NET EntityFramework的支持计划，但是，我们曾经实现过以DataSet为数据载体的数据访问框架，所以完全可以借鉴ADO.NET EF的设计思想去实现一个适度ORM数据引擎，当然这个事情得推后一点才有精力去做，但是想想就是一件多么有趣的事情啊。 &lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;上面晓之以理，下面就该动之以情了，你看这次的Android版的警务通就是用Java来搞的，没有使用那个MonoDroid吧，为啥？因为Mono for Android实在太不成熟了，用它写的程序的无论是体积还是运行效率都没法跟人家比，确实不在一个等级。总而言之，量体裁衣、具体对待。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;&lt;strong&gt;部门会餐后，俺决定从这个项目组开始逐步进行双机开发，每人配两台电脑，一台装Windows、一台装Linux，在Windows中用VS开发，调试通过后签入SVN中，再在Linux中签出使用MonoDevelop进行一遍单元测试，不用虚拟机，一切原生态同步开发，提升每个开发人员对Linux的熟悉和积累对Mono on Linux的开发经验，于公于私都是非常给力的！&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;RHEL6中MonoDevelop装不上，咱没功夫跟它耗，赶紧上OpenSUSE和CentOS，这两个都是MonoDevelop官网的主荐平台，果然很给力相当的顺。下面是今天(2011-7-5)将一些后台代码移植到Mono on Linux中的实践札记：&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;众所周知Linux的文件系统路径是区分大小写的，所以在代码中千万不能简单拼接文件路径，推荐使用 System.IO.Path 类中的相关方法进行路径操作，另外，对于文本中的分行要使用 Environment.NewLine属性，或者 AppendLine 之类的方法来处理以规避操作系统的差异。&lt;/li&gt;&#xD;
&lt;li&gt;避免使用Win32 API的P/Invoke操作，这点好在Linux上只是跑服务器端代码，所以基本不会涉及。&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;今天移植的两个类库时，只碰到下面两个问题花了一点时间，就运行测试通过了，好爽。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;一、在.NET 4.0的System.Type中新增了这个GetType(&amp;hellip;)方法重载：&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;public static&lt;/span&gt; &lt;span color="#c0504d" style="color: #c0504d;"&gt;Type&lt;/span&gt; GetType(&lt;span color="#0000ff" style="color: #0000ff;"&gt;string&lt;/span&gt; typeName, &lt;span color="#c0504d" style="color: #c0504d;"&gt;Func&lt;/span&gt;&amp;lt;&lt;span color="#c0504d" style="color: #c0504d;"&gt;AssemblyName&lt;/span&gt;, &lt;span color="#c0504d" style="color: #c0504d;"&gt;Assembly&lt;/span&gt;&amp;gt; assemblyResolver, &lt;span color="#c0504d" style="color: #c0504d;"&gt;Func&lt;/span&gt;&amp;lt;&lt;span color="#c0504d" style="color: #c0504d;"&gt;Assembly&lt;/span&gt;, &lt;span color="#0000ff" style="color: #0000ff;"&gt;string&lt;/span&gt;, &lt;span color="#0000ff" style="color: #0000ff;"&gt;bool&lt;/span&gt;, &lt;span color="#c0504d" style="color: #c0504d;"&gt;Type&lt;/span&gt;&amp;gt; typeResolver, &lt;span color="#0000ff" style="color: #0000ff;"&gt;bool&lt;/span&gt; throwOnError)&lt;/pre&gt;&#xD;
&lt;p&gt;我的代码是这样使用的：&lt;/p&gt;&#xD;
&lt;blockquote style="font-family: Courier New;"&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;public static&lt;/span&gt; &lt;span color="#c0504d" style="color: #c0504d;"&gt;Type&lt;/span&gt; GetType(&lt;span color="#0000ff" style="color: #0000ff;"&gt;string&lt;/span&gt; typeFullName)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span color="#0000ff" style="color: #0000ff;"&gt;if&lt;/span&gt;(&lt;span color="#0000ff" style="color: #0000ff;"&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(typeFullName))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span color="#0000ff" style="color: #0000ff;"&gt;return null;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return&lt;/span&gt; Type.GetType(typeFullName, assemblyName =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#c0504d" style="color: #c0504d;"&gt;Assembly&lt;/span&gt; assembly = ResolveAssembly(assemblyName);&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;if&lt;/span&gt;(assembly == &lt;span color="#0000ff" style="color: #0000ff;"&gt;null&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assembly = LoadAssembly(assemblyName);&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return&lt;/span&gt; assembly;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, &lt;span color="#0000ff" style="color: #0000ff;"&gt;null&lt;/span&gt;, &lt;span color="#0000ff" style="color: #0000ff;"&gt;false&lt;/span&gt;);&lt;br /&gt;}&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;/blockquote&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;在.NET中一切正常，但是在Mono on Linux中无法正常解析，经查看微软的源码和Mono源码后，发现他们的对于第三个typeResolver参数的处理策略不同，故而将上述代码改成：&lt;/p&gt;&#xD;
&lt;blockquote style="font-family: Courier New;"&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;public static&lt;/span&gt; &lt;span color="#c0504d" style="color: #c0504d;"&gt;Type&lt;/span&gt; GetType(&lt;span color="#0000ff" style="color: #0000ff;"&gt;string&lt;/span&gt; typeFullName)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#0000ff" style="color: #0000ff;"&gt;if&lt;/span&gt;(&lt;span color="#0000ff" style="color: #0000ff;"&gt;string&lt;/span&gt;.IsNullOrWhiteSpace(typeFullName))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return null&lt;/span&gt;;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span color="#c0504d" style="color: #c0504d;"&gt;Type&lt;/span&gt;.GetType(typeFullName, assemblyName =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#c0504d" style="color: #c0504d;"&gt;Assembly&lt;/span&gt; assembly = ResolveAssembly(assemblyName);&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;if&lt;/span&gt;(assembly == &lt;span color="#0000ff" style="color: #0000ff;"&gt;null&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assembly = LoadAssembly(assemblyName);&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return&lt;/span&gt; assembly;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, (assembly, typeName, ignoreCase) =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#0000ff" style="color: #0000ff;"&gt;if&lt;/span&gt;(assembly == null)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: #ffff00;"&gt;return null&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#0000ff" style="color: #0000ff;"&gt;else&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return&lt;/span&gt; assembly.GetType(typeName, &lt;span color="#0000ff" style="color: #0000ff;"&gt;false&lt;/span&gt;, ignoreCase);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}, &lt;span color="#0000ff" style="color: #0000ff;"&gt;false&lt;/span&gt;);&lt;br /&gt;}&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;/blockquote&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;后来发现对解析像 System.Int32 这样的简写类型名失败，原因就在于typeResolver参数对应的委托回调中传入的assembly参数为空(null)，故而将其后的代码&lt;strong&gt;(黄色高亮)&lt;/strong&gt;行改为：&lt;span face="Courier New" style="background-color: #ffff00; font-family: Courier New;"&gt;&lt;span color="#0000ff" style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span color="#c0504d" style="color: #c0504d;"&gt;Type&lt;/span&gt;.GetType(typeName, &lt;span color="#0000ff" style="color: #0000ff;"&gt;false&lt;/span&gt;, ignoreCase);&lt;/span&gt;即可！&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;二、在.NET中使用System.Net.HttpListener进行侦听后，如果进程被强制关闭Windows操作系统会回收它所占用的地址和端口&lt;em&gt;(注意：该点未经证实，纯属个人瞎猜)&lt;/em&gt;，故重新运行该程序后顺利重启HttpListener。但是在Mono on Linux中却行不通，当强制关闭进程后，再次运行会抛出 System.Net.Sockets.SocketException，提示&amp;ldquo;Address already in use.&amp;rdquo;这表示Socket已经被占用，需要手动将占用的Socket关闭，那该怎么做呢？首先查出机器中的网络状态，然后找到占用的该Socket的进程，再将该进程Kill掉即可。找到如下操作步骤可解决之：&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;在Linux终端中，键入这个命令：&lt;span face="Courier New" size="3" style="background-color: #00ff00; font-family: Courier New; font-size: small;"&gt;lsof &amp;ndash;i&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;如果当前用户不是root可能什么也看不到，那么请切换到root用户权限，如：&lt;span face="Courier New" size="3" style="background-color: #00ff00; font-family: Courier New; font-size: small;"&gt;sudo lsof -i&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;上面命令会提示你输入root根用户的密码，然后即可看到当前机器中的网络占用列表了，这时如果人品没问题的话，应该可以看到cammand为mono的占用记录，如果你清楚自己占用的端口号的话，请这么查看(以88端口为例)：&lt;span face="Courier New" size="3" style="background-color: #00ff00; font-family: Courier New; font-size: small;"&gt;lsof &amp;ndash;i:88&lt;/span&gt; 或者 &lt;span face="Courier New" size="3" style="background-color: #00ff00; font-family: Courier New; font-size: small;"&gt;sudo lsof &amp;ndash;i:88&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;你找到占用程序的进程Id(PID)，然后使用kill命令干掉它即可，假设PID为1234：&lt;span face="Courier New" size="3" style="background-color: #00ff00; font-family: Courier New; font-size: small;"&gt;kill 1234&lt;/span&gt; 或者 &lt;span face="Courier New" size="3" style="background-color: #00ff00; font-family: Courier New; font-size: small;"&gt;sudo kill 1234&lt;/span&gt;&lt;/p&gt;&#xD;
&lt;br /&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;好了，再次运行程序，又跑起来了！Good，先到这，还会有很多问题等着我们的，到时再写吧！&lt;/p&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;div style="background-color: #ffffe0; margin: 30px 20px 20px; border: navy 1px dotted; padding: 10px;"&gt;作者：&lt;span style="font-size: 14px;"&gt;钟峰(Popeye Zhong)&lt;/span&gt;目前是 &lt;a target="_blank" href="http://www.citms.com.cn/"&gt;武汉中科通达高新技术有限公司&lt;/a&gt; 的软件产品开发负责人，主要负责公司软件产品的技术架构和公共框架开发。他曾经使用 C 语言做过图形程序设计，在相当长的一段时期内从事 COM/COM+ 组件的开发和设计工作，并且短暂的做过 Lotus/Notes 和 Dialogic 语音卡程序的开发，从2003年初开始使用.NET这个充满趣味和挑战的开发平台，还领导过.NET平台下的 Windows Mobile 几个项目的开发，对WinForm和WebForm均比较熟悉。感兴趣的除了企业应用架构设计、组件开发、安全、图像处理外还对汽车和枪械模型、边境牧羊犬有浓厚的兴趣。如果希望与他联系，可访问 &lt;a target="_blank" href="http://www.cnblogs.com/sw515"&gt;http://www.cnblogs.com/sw515&lt;/a&gt; 或者Email Zongsoft # gmail.com &lt;em&gt;(将#换成@)&lt;/em&gt;。 &lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/2099505.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2011/07/06/2099505.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2011/04/11/2013104.html</id><title type="text">在Windows Mobile中检测应用程序是否运行在模拟器中</title><summary type="text">原文地址：http://blogs.msdn.com/b/netcfteam/archive/2006/09/15/756755.aspx代码如下：using System;using System.IO;using System.Windows.Forms;using Microsoft.Win32;using System.Runtime.InteropServices;using System.Text;namespace PlatformDetection{ internal partial class PInvoke { [DllImport(&amp;quot;Coredll.dll&amp;qu</summary><published>2011-04-11T15:40:00Z</published><updated>2011-04-11T15:40:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2011/04/11/2013104.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2011/04/11/2013104.html"/><content type="html">原文地址：&lt;a href="http://blogs.msdn.com/b/netcfteam/archive/2006/09/15/756755.aspx"&gt;http://blogs.msdn.com/b/netcfteam/archive/2006/09/15/756755.aspx&lt;/a&gt;&#xD;
&lt;div&gt;代码如下：&lt;/div&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;div&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; System;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; System.IO;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; System.Windows.Forms;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; Microsoft.Win32;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; System.Runtime.InteropServices;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; System.Text;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;namespace&lt;/span&gt;&lt;span style="color: #000000;"&gt; PlatformDetection&lt;br /&gt;{&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;partial&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; PInvoke&lt;br /&gt;    {&lt;br /&gt;        [DllImport(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Coredll.dll&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, EntryPoint &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;SystemParametersInfoW&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, CharSet &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; CharSet.Unicode)]&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;extern&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; SystemParametersInfo4Strings(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt;&lt;span style="color: #000000;"&gt; uiAction, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt;&lt;span style="color: #000000;"&gt; uiParam, StringBuilder pvParam, &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt;&lt;span style="color: #000000;"&gt; fWinIni);&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;enum&lt;/span&gt;&lt;span style="color: #000000;"&gt; SystemParametersInfoActions : &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;        {&lt;br /&gt;            SPI_GETPLATFORMTYPE &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;257&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; this is used elsewhere for Smartphone/PocketPC detection&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;            SPI_GETOEMINFO &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;258&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; GetOemInfo()&lt;br /&gt;        {&lt;br /&gt;            StringBuilder oemInfo &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; StringBuilder(&lt;/span&gt;&lt;span style="color: #800080;"&gt;50&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (SystemParametersInfo4Strings((&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt;&lt;span style="color: #000000;"&gt;)SystemParametersInfoActions.SPI_GETOEMINFO,&lt;br /&gt;                (&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt;&lt;span style="color: #000000;"&gt;)oemInfo.Capacity, oemInfo, &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;) &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br /&gt;                &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Exception(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Error getting OEM info.&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; oemInfo.ToString();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;partial&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; PlatformDetection&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; MicrosoftEmulatorOemValue &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Microsoft DeviceEmulator&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; IsEmulator()&lt;br /&gt;        {&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; PInvoke.GetOemInfo() &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; MicrosoftEmulatorOemValue;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; EmulatorProgram&lt;br /&gt;    {&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; Main(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;[] args)&lt;br /&gt;        {&lt;br /&gt;            MessageBox.Show(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Emulator: &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;+&lt;/span&gt;&lt;span style="color: #000000;"&gt; (PlatformDetection.IsEmulator() &lt;/span&gt;&lt;span style="color: #000000;"&gt;?&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Yes&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt; : &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;No&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/2013104.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2011/04/11/2013104.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2010/11/11/1875184.html</id><title type="text">数据库连接字符串解析的正则表达式</title><summary type="text">最近在写一个Windows Mobile的小程序，其中需要访问数据库，数据库连接字符串大致如下：Data Source=Zongsoft.MAS.sdf;Password=xxxxxx;Persist Security Info=True其中的Data Source部分指定了数据库文件的名称，但是当使用DbConnection.Open()方法进行连接时提示找不到数据库文件，经查实发现其必须指定为...</summary><published>2010-11-11T12:47:00Z</published><updated>2010-11-11T12:47:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2010/11/11/1875184.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2010/11/11/1875184.html"/><content type="html">&lt;div style="font-family: 仿宋,仿宋_gb2312; font-size: 14pt;"&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;最近在写一个Windows Mobile的小程序，其中需要访问数据库，数据库连接字符串大致如下：&lt;/p&gt;&#xD;
&lt;div style="font-family: courier new; color: maroon; font-size: 12pt; border: navy 1px solid; padding: 6px;"&gt;Data Source=Zongsoft.MAS.sdf;Password=xxxxxx;Persist Security Info=True&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;其中的&lt;span style="color: maroon;"&gt;&lt;strong&gt;Data Source&lt;/strong&gt;&lt;/span&gt;部分指定了数据库文件的名称，但是当使用&lt;span style="font-family: courier new; color: #000080;"&gt;DbConnection.Open()&lt;/span&gt;方法进行连接时提示找不到数据库文件，经查实发现其必须指定为数据库文件的完整路径。&amp;mdash;&amp;mdash;这是个麻烦事，因为手机程序部署的物理位置并不能确定，故此无法在配置文件中指定数据库文件的完整路径&lt;strong&gt;。&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;首先，我想到用&lt;span style="font-family: courier new; color: #000080;"&gt;DbConnectionStringBuilder&lt;/span&gt;来动态生成连接字符串，但是，在.NET CompactFramework 3.5中并不支持该类。退而其次发现可以使用&lt;strong&gt;DbConnection.ChangeDatabase()&lt;/strong&gt;方法来修改数据库路径，但是，经调试发现该方法只能在&lt;strong&gt;DbConnection.State&lt;/strong&gt;为&lt;strong&gt;Open&lt;/strong&gt;状态下操作，因为架构设计原因我拒绝这种野蛮方式，最后确定使用正则表达式进行动态替换，翻了下资料写出如下Regx：&lt;/p&gt;&#xD;
&lt;div style="font-family: courier new; color: maroon; font-size: 12pt; border: navy 1px solid; padding: 6px;"&gt;(?&amp;lt;=Data\s+Source\s*=\s*['"]*\s*)\w+[^;'"]+(?=\b)&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;注：如果在C#中，请将上述表达式中的双引号(")写双份，以进行字符转义。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;好吧，下面给出该方法的完整代码(C#)：&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 460px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;"&gt;&#xD;
&lt;div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum1" style="color: #606060;"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum2" style="color: #606060;"&gt;   2:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// 修复连接字符串，将数据库文件相对路径的转换为绝对路径。&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum3" style="color: #606060;"&gt;   3:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum4" style="color: #606060;"&gt;   4:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;param name="connectionString"&amp;gt;连接字符串的值。&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum5" style="color: #606060;"&gt;   5:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;returns&amp;gt;返回被修整过的连接字符串，如果无需修整则返回参数原值。&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum6" style="color: #606060;"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;string&lt;/span&gt; FixConnectionString(&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt; connectionString)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum7" style="color: #606060;"&gt;   7:&lt;/span&gt; {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum8" style="color: #606060;"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;const&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;string&lt;/span&gt; DATASOURCE_PATTERN = &lt;span style="color: #006080;"&gt;@"(?&amp;lt;=Data\s+Source\s*=\s*['"&lt;/span&gt;&lt;span style="color: #006080;"&gt;"]*\s*)\w+[^;'"&lt;/span&gt;&lt;span style="color: #006080;"&gt;"]+(?=\b)"&lt;/span&gt;;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum9" style="color: #606060;"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum10" style="color: #606060;"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty(connectionString))&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum11" style="color: #606060;"&gt;  11:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; connectionString;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum12" style="color: #606060;"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum13" style="color: #606060;"&gt;  13:&lt;/span&gt;     Match match = Regex.Match(connectionString, DATASOURCE_PATTERN, RegexOptions.IgnoreCase | RegexOptions.Singleline);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum14" style="color: #606060;"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(!match.Success)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum15" style="color: #606060;"&gt;  15:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; connectionString;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum16" style="color: #606060;"&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum17" style="color: #606060;"&gt;  17:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(Path.IsPathRooted(match.Value))&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum18" style="color: #606060;"&gt;  18:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; connectionString;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum19" style="color: #606060;"&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum20" style="color: #606060;"&gt;  20:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;string&lt;/span&gt; directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum21" style="color: #606060;"&gt;  21:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;string&lt;/span&gt; dataSource = Path.Combine(directoryName, match.Value);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum22" style="color: #606060;"&gt;  22:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum23" style="color: #606060;"&gt;  23:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; Regex.Replace(connectionString, DATASOURCE_PATTERN, dataSource, RegexOptions.IgnoreCase | RegexOptions.Singleline);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum24" style="color: #606060;"&gt;  24:&lt;/span&gt; }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/1875184.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2010/11/11/1875184.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2010/11/05/3Q.html</id><title type="text">从360与QQ之战看商业政治</title><summary type="text">作者：钟少(2010年11月4日&amp;middot;下午)博客：http://www.cnblogs.com/sw515360与QQ的鏖战至今，正式进入赤裸的贴身肉搏战了，全国人民被迫分队围观，我斗胆总结了下，各路队伍大致有：亲腾讯派、死顶360派、打酱油派、装B找抽砖家派、乐观其战唯恐不乱派。所谓&amp;ldquo;装B找抽砖家派&amp;rdquo;是以所谓这场争斗将有损中国互联网价值导向、中国兄弟不应内耗应该...</summary><published>2010-11-05T00:34:00Z</published><updated>2010-11-05T00:34:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2010/11/05/3Q.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2010/11/05/3Q.html"/><content type="html">&lt;div style="font-size: 12pt;"&gt;&#xD;
&lt;p&gt;作者：钟少(2010年11月4日&amp;middot;下午)&lt;/p&gt;&#xD;
&lt;p&gt;博客：&lt;a href="http://www.cnblogs.com/sw515"&gt;http://www.cnblogs.com/sw515&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;360与QQ的鏖战至今，正式进入赤裸的贴身肉搏战了，全国人民被迫分队围观，我斗胆总结了下，各路队伍大致有：亲腾讯派、死顶360派、打酱油派、装B找抽砖家派、乐观其战唯恐不乱派。所谓&amp;ldquo;装B找抽砖家派&amp;rdquo;是以所谓这场争斗将有损中国互联网价值导向、中国兄弟不应内耗应该共同做大一致对外(MSN?/Skype?/ICQ?)，类似于阋墙御侮之意。适下不才，跟着站队在&amp;ldquo;乐观其战唯恐不乱派&amp;rdquo;，本人没有崇高的觉悟，也讨厌被别人要求统一认识、统一思想，我只为自己的个人利益站队，只看当下之利益，不管它过去。&lt;/p&gt;&#xD;
&lt;p&gt;我这里贴出腾讯的&lt;a href="http://im.qq.com/qq_snd.shtml"&gt;《难以承受之痛的背后&amp;mdash;&amp;mdash;致QQ用户的第二封信》&lt;/a&gt;的URL：&lt;a title="http://im.qq.com/qq_snd.shtml" href="http://im.qq.com/qq_snd.shtml"&gt;http://im.qq.com/qq_snd.shtml&lt;/a&gt; 以作为我历经此次历史事件的纪念。现摘录其中部分内容作为解读：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;em&gt;&amp;ldquo;这是一个无眠之夜。是我们腾讯人度过的最痛苦和最难过的十几个小时。我们知道，在做出那个艰难的决定之后，将要直面一些用户的吃惊与不解，指责，痛骂甚至背离。我们也知道，即使你们已经做出选择，仍然会心存疑问：腾讯的反应，何至用如此激烈的方式？&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&#xD;
&lt;p&gt;何以如此？&amp;mdash;&amp;mdash;乃平日里攻城拔寨、树敌无数却防御废置；养尊处优、缺乏危机意识，突发情况致危机公关处理不当等痼疾积累所致，然奈何局势步步逼退矣。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;em&gt;&amp;ldquo;在此，请听我们诚恳地再道一声歉，为所有可能给你造成的困扰和顾虑，这样的困局，我们同样难以承受。我们清楚地记得让用户有安全稳定服务的庄重承诺，也记得12年来为了产品进步而辛苦努力的日日夜夜。如今，我们宁肯背负可能的骂名，以如此激烈的方式来表达的原因，是因为任何的劝说，舆论，正义的声音都无法遏制360没有道德底线的破坏和窃取，是因为我们已经退无可退，让无可让，我们的身后，是悬崖万丈！&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&#xD;
&lt;p&gt;12年来，QQ团队背后的付出必然是巨大，然在商言商，任何商业公司的努力和付出都是以追求利润最大化为终极目标，这是基本的经济学原理，这点如何能作为博取同情、争夺道德高点的理由？这里我要用一个最近在凤凰网的新闻案例为调味料&lt;a href="http://finance.ifeng.com/roll/20101103/2827018.shtml"&gt;《县太爷的&amp;ldquo;肺腑之言&amp;rdquo;动了谁的奶酪》&lt;/a&gt;「1日中午，中国社会科学院农村发展研究所教授于建嵘在其微博中说：&amp;ldquo;昨晚深夜赶到江西万载县，今天给七百多人讲课，号召大家不要去拆老百姓房子。刚才吃饭，县委书记陈晓平言称，为了发展，就得拆。我怒言，现代社会就是以保障个人基本权利为基础，你们这些人最要做的就是确保个人权利。他说，如果没有我们这些县委书记这样干，你们这些知识分子吃什么。&amp;rdquo;」&amp;mdash;&amp;mdash;看看人家县太爷这气势，如果您认可他老人家的观点，那么相信腾讯上面的论据您也就可以笑纳了。至于后段部分提及的&amp;ldquo;正义的声音&amp;rdquo;，那纯属政治口号、舆论讨伐，面对但凡以公义真理自居的垄断独行者，手无寸铁的闲散百姓千万要警惕，其悲惨下场古往今来犹如宿命般重复演绎着。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;em&gt;&amp;ldquo;是因为，我们看到360肆无忌惮欺压同行的行为已经愈演愈烈，早已不是两家公司的恩怨，需要有大是大非的判断，需要引起整个行业乃至政府监管部门的高度关注，在朗朗乾坤下，回到以用户利益至上的互联网发展正道。否则，只会使整个行业陷入恶性竞争，而最终受损的是你，是他，是每个热爱我们，使用我们产品的用户，是整个在勃勃兴起，谋求健康发展的互联网行业。&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在天朝这种崇尚丛林法则生存的地方，连QQ这样的巨无霸都要拿这个说事，可见现在真是很受伤啊。君不忘当年凭着强悍的南山法院的撑腰，&amp;ldquo;朗朗乾坤&amp;rdquo;下跨省搞定那个可怜的&amp;ldquo;珊瑚虫&amp;rdquo;吧？什么是&amp;ldquo;肆无忌惮&amp;rdquo;？什么是&amp;ldquo;政府监管部门的高度关注&amp;rdquo;？什么又是&amp;ldquo;用户利益至上&amp;rdquo;？&amp;mdash;&amp;mdash;丛林里向来只有弱肉强食，何来怜悯？如今大象喊着让老虎出来主持正义，讨伐狼群，这可让正义情何以堪啊？！谋求某个行业的健康发展，难道要靠垄断者良心发现的自省来拯救苍生？难道奢望这些利益联盟号召道德约束来得以保证大众利益？在油价高企的今时今日，我一直都在祈祷中石化、中石油这对患难兄弟救我于水火中，我相信他们会以德服人，但是最近听说他们决定降低柴油产量，以配合发改委更加清楚的认识到石油行业其他国际兄弟的水深火热，更加紧密的贴合国际行情。唉~ 身为中华之国民，我对这两个属于全体国民财产的公司处于日益亏损状态、艰难度日而深感不安和焦虑，对此，我的爱车只好停在楼下不开了，也算是为了不给他们日趋紧张的炼油产能增加压力、不给政府添乱吧。每天步行上班绿色低碳又环保，Oh, Yeah。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;后面还有大段大段不着边际、无关痛痒的废话，懒得一一摘录了。各位看官至此，必会有人对此忿忿不平，发表任何观点是法制民主社会之根本，您尽管不满也有权随便骂我五毛党，但是，如果您真的有写这种水文还可以收钱的路子，一定记得告诉我，钱多钱少无所畏，为谁鼓吹摇旗也不重要，只要都是炎黄子孙、没有被跨省的风险就行，俺是个现实的私利者，有得挣就好。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;再来说说360这匹恶狼吧，地球人都知道他的发家史，那就是传说中的3721，这可是个搞死人不偿命的暗器，躲不掉、甩不掉直至让你投胎重头再来，还好，当年俺仗着有点轻功，愣是没让他给黏上，不过，身边的朋友中招者云，这是一段周鸿祎的黑暗史。政治斗争是残酷的，是要死人的，主席也曾告诫同志们革命不是请客吃饭，然世界没有永远的朋友、永远的敌人，只有利益才是永恒的。很多年前，我曾经在CSDN的博客上写过一篇关于狙击百度工具条，其中还饶有介事的讲解如何手动卸载的文章，然时光荏苒，当年百度工具条的先驱、盟友&amp;mdash;&amp;mdash;周公突然变脸，连脚下的狗屎还没来得及蹭干净，就摇身一变成了为捍卫用户利益和安全而奋斗的卫士，而且是专门治理百度工具条这类流氓小商贩的城管，你说可叹不可叹？！有道是时势造枭雄，正当瑞星、金山为了各自的狗食咬得不可开交，为了利益不惜玩弄各种栽赃抹黑，使尽一切政治操弄、违法乱纪手段之后，周公已然淡定布局完毕，当下宣布免费政策一出，如已釜底抽薪，各路土豪劣绅立马傻眼，仓皇应战，岂不知大势已去，不经意间，他们早已应用的如鱼得水的抹黑伎俩纷至沓来，可料，360何等人物也？&amp;mdash;&amp;mdash;土匪中的战斗机，是有文化、玩黑金、懂政治善打黑枪的老奸巨猾，在360蓄谋已久、精心布局准备好的战场中，双方情势高下立判，金山不知死活的身披可牛这个马甲，奋勇冲前还感觉自己才是根正苗红的杀毒砖家，素不知早已落入贼人口袋，他只不过是那只用来儆猴的可怜鸡仔，像这等不思进取，靠从某个国际同盟买的杀毒内核混世道捞钱的公司，真是死不足惜，躲在后面的那个就更猥琐了，这帮人可以说是电脑界中最懂黑道权术、黑道中最懂电脑的双面侠，我等草民难得有此坐观虎斗之良机，如今捞得半两好处也算天有所赐。&lt;/p&gt;&#xD;
&lt;p&gt;360公告说要发布一个基于WebQQ的客户端软件，这真是一个绝顶聪明的反击手段，腾讯闻讯色变大呼360无耻，这WebQQ何许玩意也？从技术上讲就是可以用浏览器直接登录QQ进行聊天而不需要安装任何客户端软件。记得我以前在一家公司上班时，部门经理在路由器中把QQ客户端软件的通讯端口给屏蔽了，说是因为我们开发人员工作效率太低，原因是大家都开着QQ聊天泡MM，众所周知软件公司主要都是男丁，难得见到几个女人，然而这一堵，就像一个把所有出口全部堵上的开水壶，那个煎熬啊。于是乎，我们充分发挥自力更生、丰衣足食的优良革命传统，有上动态代理的、找销售部做代理的，而鄙人找到一个聊天软件，这个软件最牛逼的地方是他同时兼容MSN和QQ，更幸运的是它所使用的客户端通讯端口与QQ不同，这就让我得以顺利翻墙，继续着骚动的青春。要那时有WebQQ，何以如此折腾？小马哥果然好人呐，此后用WebQQ解决了不少人上Q的难题。&lt;/p&gt;&#xD;
&lt;p&gt;好吧，绕远了。刚开始我以为腾讯会将WebQQ使用的HTTP协议改成HTTPS，以避过360的强奸企图，确不曾料想小马哥以迅雷不及眼耳之势将其一把关闭，同时言辞强硬道：但凡装有360的电脑将无法同时安装QQ，并号称把这么重要的选择权交给用户，这是多么尊重用户的一个良知企业的负责行为啊，可叹可叹。万幸啊万幸，中国电力没有跟谁红脸，不然我就只能自己手摇发电来上网了。这下，看你360还如何得瑟？叫你动我的奶酪、叫你动我的桌面&amp;hellip;&amp;hellip; 360果然商场老手，见招拆招，赶紧话锋一转，发表声明，宣称自己一定将保证和QQ同时正常使用。但是他将怎么保证？&amp;mdash;&amp;mdash;这个没说，因为这个也没法说清楚，但是占领舆论制高点、博取同情的效果还是达到了。统战的重要性我们从历史中可以借鉴一二，唯恐不够乱的各路媒体和某些别有用心的人，纷纷作出各种解读，但是不管怎么解读，一个打死不肯兼容、一个死乞白赖求着兼容的两种鲜明立场大家是都看明白了，此番过招，360这个老滑头啥也没干，就是乱喷了一番口水，风向巍然呐~&lt;/p&gt;&#xD;
&lt;p&gt;我是360的老用户了，记得刚开始我是不敢用360的，因为知道周公以前的所为，但是周围的人用得多了，发现这个东西确实疗效和口碑都不错，于是乎上了贼船。西方有智人说过，大致意思是选民的记忆是短暂的，他们会为了自己的短期利益而选择看似荒谬的候选人。好吧，我承认我就是这样的短视利益者，虽然我从来都没有做过真正的选民，但却时刻幻想着做这样的准备。可自从腾讯挟几亿用户发布这样赤裸裸的胁迫后，我周围不少朋友都忧心忡忡啊，尤其是那些用习惯了免费安全软件的小白用户，让他们放弃360，还真好比让他们马上下楼裸奔一圈。我倒不大担心这个问题，因为我的MM告诉我用MSN可以继续跟她调情，别的闲杂人等不聊Q也罢，但是，腾讯还说了，装了360连QQ空间也没得玩，这可为难死我了，我现在每天唯一能跟体力劳动挂上点勾的事情就是上QQ空间种菜了。要是我卸载了QQ软件和它的IE插件还不能进空间的话，那就有古怪了，因为从技术上讲，从浏览器内部是不可能访问到我的电脑设置，也就不能判断出我有没有装360，如果能，那我就是挖地三尺也要把猫腻找出来作为证据交给360捞点好处费；同理，如果卸载360后还不能使用QQ软件，就证明周公这小子留有后门，那我就再把它的把柄找出来交给腾讯也捞点好处费，真能如此，那岂不美事？！&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在这为房价高企的纠结日子里，360与QQ上演的全武行大剧让我在围观中臆想自娱不甚快乐，也为了响应河蟹社会的口号，秉着不给ZF添乱的精神，俺来猜猜周公后面可能会展出的凌厉招数，以供各利益方提前行动做个参考吧：&lt;/p&gt;&#xD;
&lt;p&gt;1、以发布基于WebQQ的客户端软件为虚名迫使腾讯处于不利态势，迫使其自断胳膊一条；&lt;/p&gt;&#xD;
&lt;p&gt;2、基于开源的QQ通讯开发包，开发自己的通讯软件。因为是基于开源的SDK，可从法律上钻空子尽量推卸自己的责任，进可攻、退可守；&lt;/p&gt;&#xD;
&lt;p&gt;3、联合新浪、UC、阿里旺旺、国内各路SNS及山寨微博等供应商，在自己的通讯软件中一并兼容之，提升抵抗力。&lt;/p&gt;&#xD;
&lt;p&gt;在腾讯斥之法律诉讼与360的反诉讼的胶着拉锯战中，360火速推出基于开源QQ开发包的通讯软件，然后通过几亿的360装机用户安装到位，同时将这些用户的QQ信息直接转存到自己的通讯服务器，潜移默化中完成偷梁换柱的诡计，一旦旷日持久的法律诉讼失败，赔点银子拉倒，但却得到了数以亿计的用户资料，就算到时不能再兼容QQ通讯协议了，用户依然可以使用原来QQ中一样的账号和密码登录360的通讯软件，而且已经帮助广大QQ用户完成了众多好友的迁移，至于用户清不清楚这中间的过程已经不重要了。招损是损了点，管用就行，以周公无毒不丈夫的个性，应该不会太为难吧。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;360远不是当年那个可怜而卑微的&amp;ldquo;珊瑚虫&amp;rdquo;，相信再没有哪个法院的Boss愿意冒天下大不韦的政治风险进行跨省了，也只有这样势均力敌的对手PK才能演绎出如此精彩绝伦、情节蜿蜒曲折、扣人心弦的大片，但愿、但愿，大片不要草草收尾，更不要以双方握手言和、一起坐下来喝茶，不然，那可就真成为我等草寇流民的悲哀鸟。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;最后，我想起李敖这个大嘴巴说的一句名言&amp;ldquo;男人喜欢玩世上最肮脏的两种东西，一个是政治、一个是女人的阴道&amp;rdquo;，话说得真糙，理却是这么个理。同时，也想以这句话送给各位还坚持在围观第一现场中的各路队友们共勉，千万不要为了莫须有的激情伤了和气，毕竟我们围观者的利益是相同的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;------------------------------------------------------------------------------------------&lt;/p&gt;&#xD;
&lt;p&gt;声明：欢迎各路豪杰广为转载，但是本人保留五毛收入的权利，同时亦不承担任何跨省的责任与风险。&lt;/p&gt;&#xD;
&lt;p&gt;------------------------------------------------------------------------------------------&lt;/p&gt;&#xD;
&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/1869559.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2010/11/05/3Q.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2010/07/25/1784788.html</id><title type="text">我的WPF学习札记(1)</title><summary type="text">Windows Phone 7的发布日趋逼近，据说SDK开发包都已经出到beta了，虽然很久很久以前就一直有心开搞WPF，无奈惰性使然迟迟没有动作，如今倘若再不开搞，定会被如火如荼的移动时代淘汰了。再加之上次在深圳.NET俱乐部的活动中看了任旻大虾演示的QQ概念版，深为触动。本着从高从全的指导思想，打算从WPF入手然后再扩展到Silverlight和WP7。在学习过程中我打算把一些所思所得记录下来...</summary><published>2010-07-25T10:58:00Z</published><updated>2010-07-25T10:58:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2010/07/25/1784788.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2010/07/25/1784788.html"/><content type="html">&lt;div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;Windows Phone 7的发布日趋逼近，据说SDK开发包都已经出到beta了，虽然很久很久以前就一直有心开搞WPF，无奈惰性使然迟迟没有动作，如今倘若再不开搞，定会被如火如荼的移动时代淘汰了。再加之上次在深圳.NET俱乐部的活动中看了&lt;a href="#"&gt;任旻&lt;/a&gt;大虾演示的QQ概念版，深为触动。本着从高从全的指导思想，打算从WPF入手然后再扩展到Silverlight和WP7。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;在学习过程中我打算把一些所思所得记录下来，算是整理自己的思路同时也给一个爱好围观者的把戏。因为这只是个人的学习记录，其中有些代码未经调试，有些想法也是我连猜带蒙未经证实的胡思乱想，所以您且看罢了，如果真不幸给您造成了困扰、徒增了纠结，那绝对与&lt;strong&gt;微微软&lt;/strong&gt;和WPF无关，也与本人无关，特此声明。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;某个黄道吉日，俺从书柜中翻出已尘封两年左右的《WPF揭秘》(&lt;a href="http://www.china-pub.com/39340"&gt;http://www.china-pub.com/39340&lt;/a&gt;)，断续通过一个多礼拜的睡前翻读，感觉该书翻译还过得去，虽然间或有些话读起来略感别扭，但总体上还是畅顺的。期间照着书上的范例代码做了一个界面，至少已不像刚开始直接把玩WPF时有那么多的挫败感了，想当初在WPF中做个简单的界面都找不着北，积累那么多年WinForm和WebForm的经验在此完全失效，真是令人相当沮丧，因为WPF的设计完全颠覆了WinForm和WebForm中的设计理念，所以先系统的阅读WPF书籍对学习该项技术有莫大的帮助。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;属性值的类型问题&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;因为WPF为了支持XAML这种XML语言的申明式语法，使用了大量的属性，这样这些属性就可以灰常方便的在XAML中以Attribute或者Element的方式进行申明定义，而在XAML中对各种对象的属性(Property)进行赋值首先面临的一个问题是类型转换，因为XAML这种XML语言是基于纯文本格式，而这些对象属性的类型却五花八门，既有原生的.Net类型也有自定义的各种对象类型，如何将XML中的Attribute和Element文本值转化成这些目标类型呢？正好System.ComponentModel.TypeConverter 这位仁兄就是为解决这个问题而生的，其中的两个核心方法：ConvertFromString 和 ConvertTo 方法分别负责将字符串转换成目标类型和将目标类型转换成一个字符串，其实在.NET中我们有意无意都接触到过这个类，只不过通常情况下它总是在后台默默工作不为人知罢了，譬如在WinForm的设计界面中，你可以直接在某个控件的属性框中的Size属性值的输入区直接敲入『200, 100』这样一个文本，那么后台设计器其实就是调用System.Drawing.SizeConverter类将这样一个逗号分隔的文本转换成System.Drawing.Size结构的，那么为什么设计器知道使用SizeConverter类来转换呢？这是因为 Size 结构使用TypeConverterAttribute声明了它的类型转换器就为SizeConverter了，这样设计器内部就可以使用System.ComponentModel.TypeDescriptor类的GetConverter方法来获得目标类型的真实的TypeConverter类了，如果你在.NET的各种设计器中看到需要将文本转换成一些目标类型的地方，后台基本都是TypeConverter在默默支持着。当然，如果目标对象过于复杂，要将它们完全无损的转换成文本，这无论是从可读性还是可行性上讲，都是不足取的，那么对象序列化技术就孕育而生了，说到这，好像扯远了，就此打住吧。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;至此TypeConverter基本上已经能满足我们很多的应用场景了。诶，等等，如果某个对象的属性是对另外一个静态类的某个静态属性或字段的引用，这该如何使用文本来描述呢？又或者它是对运行时对象的引用，譬如是System.Type类型，这该如何是好呢？再者他引用的目标对象需要进行带参构造函数的构建，又该如何定义？这个，这个确实有点麻烦，所以WPF只好动用一个新武器了，这便是传说中的标记扩展(MarkupExtension)，他使用了一种稍微特别的语法来定义这种东西，譬如，如果我们我们希望设置某属性值为空(null)，可以如此撰写XAML：&amp;lt;Button Background=&amp;rdquo;{NullExtension}&amp;rdquo; /&amp;gt; (特注：该写法被删减过)，您看到的那对花括号中的NullExtension就是一个标记扩展类，就像.NET框架中各种直接或间接继承自的System.Attribute的各种Attribute类，我们在使用这些类的时候可以省略后面的&amp;ldquo;Attribute&amp;rdquo;单词一样，在XAML中，应用各种标记扩展类时也可以省略后面的&amp;ldquo;Extension&amp;rdquo;单词，所以如上写法可以简写成&amp;lt;Button Background=&amp;rdquo;{Null}&amp;rdquo; /&amp;gt;，呵呵，这下看起来总算舒服多了。再看一例：&amp;lt;Button Height=&amp;rdquo;{Static Member=SystemParameters.IconHeight}&amp;rdquo; /&amp;gt;这在告诉StaticExtension类去获取SystemParameters静态类的IconHeight属性值，并将该静态属性值赋值给Button的Height属性。还有一种对标记扩展类带参构造函数调用的写法，俺就不啰嗦了，MSDN上有详尽说明。看到这个地方，俺想起了俺那心爱的插件框架，里面的那个解析器(Parser)就是专干这事的，只是写法略有不同罢了，唉，真是世事多巧合啊。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;属性元素&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;这个东西比较简单，之所以把它记录在案，是因为很久很久以前，第一次翻看《WPF揭秘》一书的时候，我老记不住这个名词，要不就给记成&amp;ldquo;元素属性&amp;rdquo;了，现在之所以记得住，是因为知道了它的诞生缘由。首先我想这个东西的英文原词应该是&amp;ldquo;Property Element&amp;rdquo;吧（注：这是我瞎猜的，未经考证）。那么为啥要整这么一个概念出来咧？OK，我们来看一个例子便知：&amp;lt;Button Content=&amp;rdquo;I&amp;rsquo;m a button&amp;rdquo; /&amp;gt;，这个XAML片段定义了一个按钮，按钮的内容是一个简单的文本，就跟我们在老式UI技术中的一样，平淡无奇。好了，无法忍受平淡的WPF要发威了&amp;mdash;&amp;mdash;&amp;ldquo;翠花，上按钮&amp;rdquo;&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Padding&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="4"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Button.Content&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Ellipse&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="140"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Height&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="40"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Stroke&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Red"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Fill&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Yellow"&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;VerticalAlignment&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Center"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Center"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;I'm a evil button&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;TextBlock&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;Button.Content&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;Button&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;好吧，我承认有一点按钮强迫症。这个邪恶的按钮里面被塞入了一个红色边框黄色背景的圆圈，中间还有一个文本，如果你比我更疯狂，还可以在里面继续放颗槟榔什么的。里面那个&amp;lt;Button.Content&amp;gt;此时就是属性元素的写法了，为啥叫属性元素呢，因为它表示Button的Content属性(Property)，而这个属性是对应到XAML中的一个Element(元素)节点的，故而名为此。那么为啥要用元素(Element)的写法呢？那是因为XML的Attribute写法已经不堪重负，就算用TypeConverter也搞不定了这么复杂的描述了。再次强行插入一则广告：这跟俺在插件框架中的Builtin与子Builtin如出一辙，乖乖，莫非真存在心有灵犀这样的传说？&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;附加属性的XAML写法&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;当初为了在WPF中试验一个简单的界面，我需要使用到Docking布局，好歹是只玩弄WinForm多年的老菜鸟了，所以直接去某个简单控件中找Dock属性，乖乖一顿好找居然没找到，最终我在某个犄角旮旯发现了一个叫DockPanel的家伙，把它拖出来，然后再把俺的习惯性按钮添加进去，神奇的事情发生鸟，在这个按钮中突然崩出来一个叫DockPanel.Dock的属性来，至此佳节之际我想起一个久违的术语：扩展控件，在WinForm中，按钮是没有ToolTip这样的属性的，但是如果在窗体中放置一个ToolTip组件的话，那么该窗体中所有的控件都会出现一个神奇的&amp;ldquo;ToolTip上的ToolTip&amp;rdquo;属性，而ToolTip控件就叫扩展控件，所谓扩展控件就是实现了IExtenderProvider接口的组件或控件类。在WPF中的DockPanel与子控件的Dock交互跟WinForm里面的扩展控件的用法是不是很像呢？不过，经过后面阅读，我知道他们的内部机制可就完全没有可比性了，不要怪我老是拿WinForm来比照，你明白的，人的思维惯性是灰常强大的，不是变态一般是把控不了的。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;赶紧回到刚才那个WPF中的按钮上来，现在我终于可以在设计视图中的属性框内设置按钮的Dock值了，设置成功后，在XAML中看起来就是这个样子：&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;DockPanel&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="400"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Height&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="400"&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;DockPanel.Dock&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Top"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="1.Top"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Height&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="40"&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;DockPanel.Dock&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="Left"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="2.Left"&lt;/span&gt; &lt;span style="color: #ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;="40"&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;DockPanel&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;如上XAML片段用C#代码来写，大致如下(略有删减)：&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="border: gray 1px solid; padding: 0.5em;"&gt;&#xD;
&lt;div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: navy;"&gt;DockPanel&lt;/span&gt; panel = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; DockPanel();&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span style="color: navy;"&gt;Button&lt;/span&gt; button1 = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; Button()&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;{&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;Content = &lt;span style="color: #006080;"&gt;"1.Top"&lt;/span&gt;,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;Height = 40,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;};&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span style="color: navy;"&gt;Button&lt;/span&gt; button2 = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; Button()&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;{&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;Content = &lt;span style="color: #006080;"&gt;"2.Left"&lt;/span&gt;,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;Width = 40,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;};&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;DockPanel.SetDock(button1, System.Windows.Controls.Dock.Top);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;DockPanel.SetDock(button2, System.Windows.Controls.Dock.Left);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;依赖属性&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;开发WPF程序，首推使用XAML，而在XAML中嵌入代码是件非常糟糕的事情，对此你可以回想下在ASP那个水深火热的旧社会中广大Coder们的悲惨生活。现在XAML的这个新时代，各种属性把劳苦的我们解放出来，但是传统的属性不具备灵活的通知机制，所以WPF推出了伟大的依赖属性和附加属性这么个核武器，事实上附加属性只是依赖属性的另一种形式的包装。它到底有多强悍，在此不表，因各种资料中都有详尽掐媚炫夸之辞。总之，在WPF的各种技术特性中它无时无刻无处不在，因此如果对依赖属性没有细致深入的理解，越学习到后面越是感觉如处迷雾中，但见远处的光亮却无从走近，所以我决定先停下来，把这个东西彻底搞清楚再继续前行。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;因为编译器的各种处理，使得Reflector反编译出来源码不便阅读，因此我上微微软网站（请猛击此处：&lt;a href="http://referencesource.microsoft.com/netframework.aspx"&gt;http://referencesource.microsoft.com/netframework.aspx&lt;/a&gt;）下载了.NET 4.0的源码。可惜，微微软提供的源码是供调试之用，因此没有以项目的形式进行包装组织，这点让人很是纠结，不知哪位兄弟有完整的像类似于SharpDevelop源码包这样的下载地址，还请不吝赐予。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;OK，先上DependencyProperty类的Register方法：&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="border: lightgray 1px solid; padding: 0.5em;"&gt;&#xD;
&lt;div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum1" style="color: #606060;"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; DependencyProperty Register(&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt; name, &lt;span style="color: blue;"&gt;Type&lt;/span&gt; propertyType, &lt;span style="color: blue;"&gt;Type&lt;/span&gt; ownerType,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;PropertyMetadata&lt;/span&gt; typeMetadata, &lt;span style="color: blue;"&gt;ValidateValueCallback&lt;/span&gt; validateValueCallback)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum2" style="color: #606060;"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum3" style="color: #606060;"&gt;   3:&lt;/span&gt;     RegisterParameterValidation(name, propertyType, ownerType);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum4" style="color: #606060;"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum5" style="color: #606060;"&gt;   5:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;//Register an attached property&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum6" style="color: #606060;"&gt;   6:&lt;/span&gt;     &lt;span style="color: blue;"&gt;PropertyMetadata&lt;/span&gt; defaultMetadata = &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum7" style="color: #606060;"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(typeMetadata != &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; typeMetadata.DefaultValueWasSet())&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum8" style="color: #606060;"&gt;   8:&lt;/span&gt;     {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum9" style="color: #606060;"&gt;   9:&lt;/span&gt;         defaultMetadata = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; PropertyMetadata(typeMetadata.DefaultValue);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum10" style="color: #606060;"&gt;  10:&lt;/span&gt;     }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum11" style="color: #606060;"&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum12" style="color: #606060;"&gt;  12:&lt;/span&gt;     &lt;span style="color: blue;"&gt;DependencyProperty&lt;/span&gt; property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum13" style="color: #606060;"&gt;  13:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum14" style="color: #606060;"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(typeMetadata != &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum15" style="color: #606060;"&gt;  15:&lt;/span&gt;     {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum16" style="color: #606060;"&gt;  16:&lt;/span&gt;         &lt;span style="color: #008000;"&gt;//Apply type-specific metadata to owner type only&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum17" style="color: #606060;"&gt;  17:&lt;/span&gt;         property.OverrideMetadata(ownerType, typeMetadata);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum18" style="color: #606060;"&gt;  18:&lt;/span&gt;     }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum19" style="color: #606060;"&gt;  19:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum20" style="color: #606060;"&gt;  20:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; property;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum21" style="color: #606060;"&gt;  21:&lt;/span&gt; }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;该注册方法还有另外两个分别忽略最后两个参数的重载，即后两个参数可以为空(null)。该方法内部调用的第一个方法为RegisterParameterValidation，这只是一个检测前三个参数是否有效的验证方法，如果其中任何一个为空则抛出异常而已。第7行判断第三个类型为PropertyMetadata的参数是否不为空并且已经设置了默认值，如果是，则创建一个另外一个名为defaultMetadata的属性元数据对象，这里为啥要另外创建而不直接使用参数引用的那个PropertyMetadata对象呢？让我们先跟进去看看PropertyMetadata类的构造函数吧，这个构造函数只是简单将输入参数直接赋值给其DefaultValue属性而已，该属性代码如下：&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper"&gt;&#xD;
&lt;div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum1" style="color: #606060;"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;object&lt;/span&gt; DefaultValue&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum2" style="color: #606060;"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum3" style="color: #606060;"&gt;   3:&lt;/span&gt;     get&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum4" style="color: #606060;"&gt;   4:&lt;/span&gt;     {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum5" style="color: #606060;"&gt;   5:&lt;/span&gt;         DefaultValueFactory defaultFactory = _defaultValue &lt;span style="color: #0000ff;"&gt;as&lt;/span&gt; DefaultValueFactory;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum6" style="color: #606060;"&gt;   6:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(defaultFactory == &lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum7" style="color: #606060;"&gt;   7:&lt;/span&gt;         {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum8" style="color: #606060;"&gt;   8:&lt;/span&gt;             &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; _defaultValue;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum9" style="color: #606060;"&gt;   9:&lt;/span&gt;         }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum10" style="color: #606060;"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;else&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum11" style="color: #606060;"&gt;  11:&lt;/span&gt;         {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum12" style="color: #606060;"&gt;  12:&lt;/span&gt;             &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; defaultFactory.DefaultValue;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum13" style="color: #606060;"&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum14" style="color: #606060;"&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum15" style="color: #606060;"&gt;  15:&lt;/span&gt;     set&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum16" style="color: #606060;"&gt;  16:&lt;/span&gt;     {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum17" style="color: #606060;"&gt;  17:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(Sealed)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum18" style="color: #606060;"&gt;  18:&lt;/span&gt;         {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum19" style="color: #606060;"&gt;  19:&lt;/span&gt;             &lt;span style="color: #0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; InvalidOperationException(SR.Get(SRID.TypeMetadataCannotChangeAfterUse));&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum20" style="color: #606060;"&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum21" style="color: #606060;"&gt;  21:&lt;/span&gt;  &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum22" style="color: #606060;"&gt;  22:&lt;/span&gt;         &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;(&lt;span style="color: #0000ff;"&gt;value&lt;/span&gt; == DependencyProperty.UnsetValue)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum23" style="color: #606060;"&gt;  23:&lt;/span&gt;         {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum24" style="color: #606060;"&gt;  24:&lt;/span&gt;             &lt;span style="color: #0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; ArgumentException(SR.Get(SRID.DefaultValueMayNotBeUnset));&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum25" style="color: #606060;"&gt;  25:&lt;/span&gt;         }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum26" style="color: #606060;"&gt;  26:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum27" style="color: #606060;"&gt;  27:&lt;/span&gt;         _defaultValue = &lt;span style="color: #0000ff;"&gt;value&lt;/span&gt;;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum28" style="color: #606060;"&gt;  28:&lt;/span&gt;  &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum29" style="color: #606060;"&gt;  29:&lt;/span&gt;         SetModified(MetadataFlags.DefaultValueModifiedID);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum30" style="color: #606060;"&gt;  30:&lt;/span&gt;     }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum31" style="color: #606060;"&gt;  31: &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;在属性里面使用了DefaultValueFactory类，这是一个内部的抽象类，里面有两个抽象成员：CreateDefaultValue方法和DefaultValue只读属性，为啥要动用这么个东西来处理简单的默认值呢？我估计是因为在不同的依赖对象中可能需要对不同的依赖属性使用不同策略的默认值创建方式，那么可以定义不同创建策略的默认值实体工厂类来处理吧。在getter中，如果属性变量保存的默认值为DefaultValueFactory类型，则使用该工厂提供的默认值，否则直接返回对应的成员变量。在setter中，首先判断Sealed属性，顾名思义Sealed表示该PropertyMetadata修饰的依赖属性是否已经被封闭，若为真，则不允许更改其默认值（即抛出异常）。那么大致来看看该Sealed属性实现及其相关的其他代码吧：&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;"&gt;&#xD;
&lt;div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum1" style="color: #606060;"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000;"&gt;// PropertyMetadata, UIPropertyMetadata, and FrameworkPropertyMetadata.&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum2" style="color: #606060;"&gt;   2:&lt;/span&gt; [FriendAccessAllowed] &lt;span style="color: #008000;"&gt;// Built into Base, also used by Core and Framework.&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum3" style="color: #606060;"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt; MetadataFlags _flags;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum4" style="color: #606060;"&gt;   4:&lt;/span&gt;  &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum5" style="color: #606060;"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; SetModified(MetadataFlags id) { _flags |= id; }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum6" style="color: #606060;"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; IsModified(MetadataFlags id) { &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; (id &amp;amp; _flags) != 0; } &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum7" style="color: #606060;"&gt;   7:&lt;/span&gt;  &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum8" style="color: #606060;"&gt;   8:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum9" style="color: #606060;"&gt;   9:&lt;/span&gt; &lt;span style="color: #008000;"&gt;///     Write a flag value &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum10" style="color: #606060;"&gt;  10:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum11" style="color: #606060;"&gt;  11:&lt;/span&gt; [FriendAccessAllowed] &lt;span style="color: #008000;"&gt;// Built into Base, also used by Core and Framework.&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum12" style="color: #606060;"&gt;  12:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; WriteFlag(MetadataFlags id, &lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;value&lt;/span&gt;)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum13" style="color: #606060;"&gt;  13:&lt;/span&gt; { &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum14" style="color: #606060;"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color: #0000ff;"&gt;value&lt;/span&gt;)&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum15" style="color: #606060;"&gt;  15:&lt;/span&gt;     { &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum16" style="color: #606060;"&gt;  16:&lt;/span&gt;         _flags |= id; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum17" style="color: #606060;"&gt;  17:&lt;/span&gt;     }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum18" style="color: #606060;"&gt;  18:&lt;/span&gt;     &lt;span style="color: #0000ff;"&gt;else&lt;/span&gt; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum19" style="color: #606060;"&gt;  19:&lt;/span&gt;     {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum20" style="color: #606060;"&gt;  20:&lt;/span&gt;         _flags &amp;amp;= (~id);&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum21" style="color: #606060;"&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum22" style="color: #606060;"&gt;  22:&lt;/span&gt; } &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum23" style="color: #606060;"&gt;  23:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum24" style="color: #606060;"&gt;  24:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;summary&amp;gt; &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum25" style="color: #606060;"&gt;  25:&lt;/span&gt; &lt;span style="color: #008000;"&gt;///     Read a flag value &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum26" style="color: #606060;"&gt;  26:&lt;/span&gt; &lt;span style="color: #008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum27" style="color: #606060;"&gt;  27:&lt;/span&gt; [FriendAccessAllowed] &lt;span style="color: #008000;"&gt;// Built into Base, also used by Core and Framework. &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum28" style="color: #606060;"&gt;  28:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; ReadFlag(MetadataFlags id) { &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; (id &amp;amp; _flags) != 0; }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum29" style="color: #606060;"&gt;  29:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum30" style="color: #606060;"&gt;  30:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;bool&lt;/span&gt; Sealed&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum31" style="color: #606060;"&gt;  31:&lt;/span&gt; { &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum32" style="color: #606060;"&gt;  32:&lt;/span&gt;     [FriendAccessAllowed] &lt;span style="color: #008000;"&gt;// Built into Base, also used by Core.&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum33" style="color: #606060;"&gt;  33:&lt;/span&gt;     get { &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; ReadFlag(MetadataFlags.SealedID); } &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum34" style="color: #606060;"&gt;  34:&lt;/span&gt;     set { WriteFlag(MetadataFlags.SealedID, &lt;span style="color: #0000ff;"&gt;value&lt;/span&gt;); } &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum35" style="color: #606060;"&gt;  35:&lt;/span&gt; }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;"&gt;&#xD;
&lt;div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum1" style="color: #606060;"&gt;   1:&lt;/span&gt; [FriendAccessAllowed] &lt;span style="color: #008000;"&gt;// Built into Base, also used by Core and Framework. &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum2" style="color: #606060;"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;enum&lt;/span&gt; MetadataFlags : &lt;span style="color: #0000ff;"&gt;uint&lt;/span&gt; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum3" style="color: #606060;"&gt;   3:&lt;/span&gt; {&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum4" style="color: #606060;"&gt;   4:&lt;/span&gt;     DefaultValueModifiedID = 0x00000001, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum5" style="color: #606060;"&gt;   5:&lt;/span&gt;     SealedID  = 0x00000002,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum6" style="color: #606060;"&gt;   6:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused = 0x00000004,&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum7" style="color: #606060;"&gt;   7:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused = 0x00000008,&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum8" style="color: #606060;"&gt;   8:&lt;/span&gt;     Inherited = 0x00000010, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum9" style="color: #606060;"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum10" style="color: #606060;"&gt;  10:&lt;/span&gt;     UI_IsAnimationProhibitedID = 0x00000020, &lt;span style="color: #008000;"&gt;// True if peer refers to an owner's animation peer property; False if Peer refers to the animation peer's owner property &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum11" style="color: #606060;"&gt;  11:&lt;/span&gt;  &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum12" style="color: #606060;"&gt;  12:&lt;/span&gt;     FW_AffectsMeasureID                 = 0x00000040,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum13" style="color: #606060;"&gt;  13:&lt;/span&gt;     FW_AffectsArrangeID                 = 0x00000080, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum14" style="color: #606060;"&gt;  14:&lt;/span&gt;     FW_AffectsParentMeasureID           = 0x00000100,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum15" style="color: #606060;"&gt;  15:&lt;/span&gt;     FW_AffectsParentArrangeID           = 0x00000200,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum16" style="color: #606060;"&gt;  16:&lt;/span&gt;     FW_AffectsRenderID                  = 0x00000400,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum17" style="color: #606060;"&gt;  17:&lt;/span&gt;     FW_OverridesInheritanceBehaviorID   = 0x00000800, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum18" style="color: #606060;"&gt;  18:&lt;/span&gt;     FW_IsNotDataBindableID              = 0x00001000,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum19" style="color: #606060;"&gt;  19:&lt;/span&gt;     FW_BindsTwoWayByDefaultID           = 0x00002000, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum20" style="color: #606060;"&gt;  20:&lt;/span&gt;     FW_ShouldBeJournaledID              = 0x00004000, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum21" style="color: #606060;"&gt;  21:&lt;/span&gt;     FW_SubPropertiesDoNotAffectRenderID = 0x00008000,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum22" style="color: #606060;"&gt;  22:&lt;/span&gt;     FW_SubPropertiesDoNotAffectRenderModifiedID = 0x00010000, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum23" style="color: #606060;"&gt;  23:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x00020000,&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum24" style="color: #606060;"&gt;  24:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x00040000,&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum25" style="color: #606060;"&gt;  25:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x00080000,&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum26" style="color: #606060;"&gt;  26:&lt;/span&gt;     FW_InheritsModifiedID                       = 0x00100000, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum27" style="color: #606060;"&gt;  27:&lt;/span&gt;     FW_OverridesInheritanceBehaviorModifiedID   = 0x00200000,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum28" style="color: #606060;"&gt;  28:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x00400000, &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum29" style="color: #606060;"&gt;  29:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x00800000, &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum30" style="color: #606060;"&gt;  30:&lt;/span&gt;     FW_ShouldBeJournaledModifiedID              = 0x01000000,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum31" style="color: #606060;"&gt;  31:&lt;/span&gt;     FW_UpdatesSourceOnLostFocusByDefaultID      = 0x02000000, &lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum32" style="color: #606060;"&gt;  32:&lt;/span&gt;     FW_DefaultUpdateSourceTriggerModifiedID     = 0x04000000,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum33" style="color: #606060;"&gt;  33:&lt;/span&gt;     FW_ReadOnlyID                               = 0x08000000,&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum34" style="color: #606060;"&gt;  34:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x10000000,&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum35" style="color: #606060;"&gt;  35:&lt;/span&gt;     &lt;span style="color: #008000;"&gt;// Unused    = 0x20000000, &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum36" style="color: #606060;"&gt;  36:&lt;/span&gt;     FW_DefaultUpdateSourceTriggerEnumBit1       = 0x40000000, &lt;span style="color: #008000;"&gt;// Must match constants used in FrameworkPropertyMetadata&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum37" style="color: #606060;"&gt;  37:&lt;/span&gt;     FW_DefaultUpdateSourceTriggerEnumBit2       = 0x80000000, &lt;span style="color: #008000;"&gt;// Must match constants used in FrameworkPropertyMetadata &lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&#xD;
&lt;pre&gt;&lt;span id="lnum38" style="color: #606060;"&gt;  38:&lt;/span&gt; }&lt;/pre&gt;&#xD;
&lt;!--CRLF--&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;Sealed属性就是调用ReadFlag和WriteFlag这两个内部方法进行状态读写操作，那么这个_flags变量和MetadataFlags枚举是啥意思呢？这其实是典型的使用二进制掩码的方式进行标记/状态判断的一种编码风格，这种方式在C/C++语言中使用的比较广泛，主要的好处就是比较节约内存，尤其是在较多状态开关的类中能以一种相对统一的方式进行设置或取值。对二进制和十六进制略有了解的童鞋应该都能看明白，我就不啰嗦了。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;同时在setter中有个判断&amp;ldquo;if(value == DependencyProperty.UnsetValue)&amp;rdquo;，这个DependencyProperty.UssetValue是个啥？&lt;/p&gt;&#xD;
&lt;div id="codeSnippetWrapper"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;object&lt;/span&gt; UnsetValue = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; NamedObject(&lt;span style="color: #006080;"&gt;"DependencyProperty.UnsetValue"&lt;/span&gt;);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;UnsetValue字段是单例模式的命名对象，语意上表示一个未设置的值。因为任何时刻我们可以查看任何一个依赖属性的值是否等于DependencyProperty.UnsetValue单例对象来判断其属性值是否被设置过，故此，也必须确保默认值不能为该单例对象。因为NamedObject类只是个标记性的描述类，所以可以想见其代码非常简单，这里就不再贴出来了。&lt;/p&gt;&#xD;
&lt;p style="text-indent: 2em;"&gt;好了，让我们再回到DependencyProperty类的Register方法中来，其12行调用了RegisterCommon方法，这是个私有方法，也是真正干活的地方，具体怎么个干法呢，且待俺继续琢磨琢磨&amp;hellip;&amp;hellip;&lt;/p&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div style="background-color: #ffffe0; margin: 4em 1em 1em; border: gray 1px dotted; padding: 0.5em;"&gt;作者：钟峰(Popeye Zhong)目前是 &lt;a target="_blank" href="http://www.sz-accp.net/"&gt;北大青鸟（深圳中青）培训中心&lt;/a&gt; 的ACCP讲师，负责讲授.NET和SQL数据库开发课程。他曾经使用 C 语言做过图形程序设计，在相当长的一段时期内从事 COM/COM+ 组件的开发和设计工作，并且短暂的做过 Lotus/Notes 和 Dialogic 语音卡程序的开发，从2003年初开始使用.NET这个充满趣味和挑战的开发平台，还领导过.NET平台下的 Windows Mobile 几个项目的开发，对WinForm和WebForm均比较熟悉。感兴趣的除了企业应用架构设计、组件开发、安全、图像处理外还对汽车和枪械模型、边境牧羊犬有浓厚的兴趣。如果希望与他联系，可访问 &lt;a target="_blank" href="http://www.cnblogs.com/sw515"&gt;http://www.cnblogs.com/sw515&lt;/a&gt; 或者Email Zongsoft # gmail.com &lt;em&gt;(将#换成@)&lt;/em&gt;。 &lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/1784788.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2010/07/25/1784788.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2010/07/09/1774483.html</id><title type="text">关于委托(Delegate)的一个记录</title><summary type="text">混了这么久的C#，自以为对 Delegate 和 event 这样的基本概念已经了然于胸，却不曾想最近被一个这么基本特性给狠狠绊了一跤，实在是愧对天人，特此将这个问题暴露出来，警醒自己也提醒路人。 窗体的后台代码如下：[代码]原本以为对同一个对象的同一事件进行同一方法的多次挂载(+=)，不会造成该事件处理函数被重复加入到事件列表中，即如上代码，如果多次点击&amp;#8220;添加Delegate&amp;#82...</summary><published>2010-07-09T08:48:00Z</published><updated>2010-07-09T08:48:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2010/07/09/1774483.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2010/07/09/1774483.html"/><content type="html">&lt;p&gt;混了这么久的C#，自以为对 Delegate 和 event 这样的基本概念已经了然于胸，却不曾想最近被一个这么基本特性给狠狠绊了一跤，实在是愧对天人，特此将这个问题暴露出来，警醒自己也提醒路人。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/SW515/WindowsLiveWriter/Delegate_EB05/%E6%97%A0%E6%A0%87%E9%A2%98_2.png" target="_blank"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="无标题" border="0" alt="无标题" src="http://images.cnblogs.com/cnblogs_com/SW515/WindowsLiveWriter/Delegate_EB05/%E6%97%A0%E6%A0%87%E9%A2%98_thumb.png" width="244" height="113" /&gt;&lt;/a&gt; &lt;/p&gt;&#xD;
&lt;p&gt;窗体的后台代码如下：&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;!--&lt;br/ /&gt;&#xD;
&lt;br/ /&gt;&#xD;
Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br/ /&gt;&#xD;
http://www.CodeHighlighter.com/&lt;br/ /&gt;&#xD;
&lt;br/ /&gt;&#xD;
--&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;1&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;btnDelegateAdd1_Click(&lt;/span&gt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;sender,&amp;nbsp;EventArgs&amp;nbsp;e)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;2&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;3&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button1.Click&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;+=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;EventHandler(button1_Click);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;4&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;5&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;6&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;btnDelegateAdd2_Click(&lt;/span&gt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;sender,&amp;nbsp;EventArgs&amp;nbsp;e)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;7&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;8&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button2.Click&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;+=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;9&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;10&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageBox.Show(&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;我是按钮&amp;nbsp;2&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;匿名方法&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;11&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;12&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;13&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;14&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;button1_Click(&lt;/span&gt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;sender,&amp;nbsp;EventArgs&amp;nbsp;e)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;15&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;16&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageBox.Show(&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;我是按钮&amp;nbsp;1&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;普通方法&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;17&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="font-family: courier new; font-size: 11pt"&gt;原本以为对同一个对象的同一事件进行同一方法的多次挂载(+=)，不会造成该事件处理函数被重复加入到事件列表中，即如上代码，如果多次点击&amp;#8220;&lt;strong&gt;添加Delegate&lt;/strong&gt;&amp;#8221;和&amp;#8220;&lt;strong&gt;添加匿名Delegate&lt;/strong&gt;&amp;#8221;按钮后，不会在点击下面相应测试按钮时，导致多次执行。之所以有这种自以为，是觉得这样的重复加入没有意义，事件的add和remove内置方法会负责判断处理函数是否已在事件列表之中，却不曾想，这样的假设实在是越俎代庖。&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;如果不希望多次重复挂载事件处理的话，需要自己做出判断，譬如上面的&lt;span style="font-family: Courier"&gt;&lt;strong&gt;btnDelegateAdd1&lt;/strong&gt;&lt;/span&gt;按钮事件可以这么写：&lt;/p&gt;&#xD;
&lt;div style="font-family: courier new"&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;!--&lt;br/ /&gt;&#xD;
&lt;br/ /&gt;&#xD;
Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br/ /&gt;&#xD;
http://www.CodeHighlighter.com/&lt;br/ /&gt;&#xD;
&lt;br/ /&gt;&#xD;
--&gt;&lt;span style="color: #008080"&gt;1&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;btnDelegateAdd1_Click(&lt;/span&gt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;sender,&amp;nbsp;EventArgs&amp;nbsp;e)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;2&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;3&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button1.Click&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;-=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;EventHandler(button1_Click);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;4&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button1.Click&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;+=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;EventHandler(button1_Click);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #008080"&gt;5&lt;/span&gt;&amp;nbsp;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&#xD;
&lt;p&gt;但是，&lt;span style="font-family: Courier"&gt;&lt;strong&gt;btnDelegateAdd2&lt;/strong&gt;&lt;/span&gt;按钮事件中使用的是匿名方法，就没办法这样直接卸载事件处理函数了。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/1774483.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2010/07/09/1774483.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2010/04/23/1718262.html</id><title type="text">我的插件框架&amp;#183;前传</title><summary type="text">初识话说很久很久以前，当我还是只菜菜鸟的时候，就说听过关于插件的传说。因为一直都是做富客户端模式的企业应用软件，所以对插件这种神奇的搭积木式的挂接模式，无限向往之。再后来，听说了有关Eclipse的种种神奇传说，与日中天的名气令其在坊间一度被尊为神器，就连俺这么闭塞的.NET粉丝都能把它的名字正确拼写出来，由此可见一番，终于在某个风高月夜伸手不见五指的大白天，俺把罪恶的手伸向了她那被万人膜拜的&amp;#...</summary><published>2010-04-22T18:05:00Z</published><updated>2010-04-22T18:05:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2010/04/23/1718262.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2010/04/23/1718262.html"/><content type="html">&lt;p&gt;&lt;strong&gt;初识&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;话说很久很久以前，当我还是只菜菜鸟的时候，就说听过关于插件的传说。因为一直都是做富客户端模式的企业应用软件，所以对插件这种神奇的搭积木式的挂接模式，无限向往之。再后来，听说了有关Eclipse的种种神奇传说，与日中天的名气令其在坊间一度被尊为神器，就连俺这么闭塞的.NET粉丝都能把它的名字正确拼写出来，由此可见一番，终于在某个风高月夜伸手不见五指的大白天，俺把罪恶的手伸向了她那被万人膜拜的&amp;#8230;&lt;/p&gt;&#xD;
&lt;p&gt;首先找了一些Eclipse的插件开发资料，硬着头皮看了些Java的代码后，始终不得要领，大部分的插件开发资料都属于依葫芦画瓢的讲解方式，而对Eclipse插件架构的整体描述几无涉及，官方的资料中对整体架构的介绍也是粗略含糊，就我这Java门外汉来说，想要通过代码对其有高屋建瓴的理解还真是不靠谱，苦熬之下也便不了了之。然哥早已不在江湖，却依然流传着Eclipse的传说&amp;#8230;&amp;#8230;&lt;/p&gt;&#xD;
&lt;p&gt;时光荏苒，就在某个不经意的日子，突然晴天一声雷，一个名叫SharpDevelop的家伙半道杀出，在.NET社团掀起一阵骚动，趋之者无数，也再次撩动起我不甘寂寞的心，于是乎，历史再度上演&amp;#8230;&lt;/p&gt;&#xD;
&lt;p&gt;可怜SharpDevelop官方几乎没有提供有什么价值的文档，网上的资料除了一点介绍性的文字外就剩旁边的广告链接了。也罢，直接看源码吧，也没什么比C#代码更能讲清楚问题的了。SharpDevelop早期0.x版本的代码，坦白说，写得还真是那个啥，跟了跟它的代码，基本流程是清楚了，但是对一些关键问题的疑惑还是没有解决&lt;em&gt;（唉，看来俺的智商还是没有自诩的那么高啊，鄙视一下），&lt;/em&gt;问题主要有下：&lt;/p&gt;&#xD;
&lt;p&gt;1、插件节点(PluginNode)与插件(Plugin)以及代码子(Codon)这三角关系究竟隐藏着啥名堂？&lt;/p&gt;&#xD;
&lt;p&gt;2、Doozer&lt;em&gt;(这个不知道咋翻译了)&lt;/em&gt;到底主司何职？它到底对Codon负责了什么？如果说他是Codon的构建器，那为啥Codon中还要有BuildItem方法，是不是功能重叠？&lt;/p&gt;&#xD;
&lt;p&gt;3、Codon中的BuildItem方法中还包含有ArrayList类型的subItems，难道是父Codon负责子Codon的创建？父创建子，势必会造成父对子的依赖，如果这样的话，第三方开发人员如果想要基于已有插件进行功能扩展的话，已有插件是不可能了解子Codon的创建行为的，那么这个subItems参数岂不是鸡肋或摆设？再则，如果父Codon只是调用子Codon的BuildItem方法，由子Codon自行构建，那么父如何确保以正确的方式将子Codon挂接进插件树中？&lt;/p&gt;&#xD;
&lt;p&gt;4、插件如何获得环境信息？并如何确保扩展插件不会对依赖插件过度耦合？&lt;/p&gt;&#xD;
&lt;p&gt;5、消息通知机制如何处理？如何将插件自身提供的一些公共信息提供给其他插件共享？插件状态发生改变，如何以一种统一并无耦合的方式通知给感兴趣的其他插件？插件运行时平台如何将事件消息传递给订阅者，在传递过程中，如何以灵活的方式注入进去进行过滤处理？&lt;/p&gt;&#xD;
&lt;p&gt;6、是不是每个Codon都要有对应自己的Doozer？在很多时候，可能需要创建不同的对象，但是这些对象有很大的共性，只是创建过程和后续初始化有差异，如何使用一个Doozer来做到这点？如果一个插件想提供一个服务给其他插件使用，其他插件是不是只能通过接口引用的方式进行解偶？这样的方式，耦合度是不是还可以继续降低？&lt;/p&gt;&#xD;
&lt;p&gt;以上是当初的一部分问题，可能描述的还是笼统了，虽然陆续阅读源码，某些问题有了答案，但是对整个架构的理解还是不能很好的串联起来，故而就算能基于SharpDevelop进行插件开发了，也总有暗箱操作的不安。另外，SharpDevelop中到处充斥着各种条件选择(Condition)，尤其是定义某些复杂Codon的时候，各种各样的Condition缠绕四处很是混乱不干净，当时虽说不出具体有啥特别不好，但却总觉有种坏味道隐隐围绕，是不是应该有更好方式来解决Codon按条件进行挂载的问题呢？&lt;/p&gt;&#xD;
&lt;p&gt;带着这些问题，断断续续的纠结了一阵，我的惰性最终在时间的飞逝中发挥出它应有贡献，而江湖的风骚过后大家该吃吃该喝喝，歌舞升平依旧，社会一片和谐，总之形势大好。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;起因&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;2008年上，经朋友介绍去到一家Mini型软件公司负责一个管理软件的产品开发，当初该老板介绍的前景不错，待遇也可以，俺屁颠屁颠的带上吃饭的家伙就杀过去了。由于对这个行业不了解以及过度自信，当初也跟着老板喊了不少口号、放了不少卫星&lt;em&gt;(汗一个)&lt;/em&gt;。还不错，手下有两个程序员可以使唤（&lt;em&gt;其中一个是从ACCP带过去的学生，小伙非常优秀，2009年底已经出来自己创业了，他们的Ideal非常棒，祝福他们）&lt;/em&gt;，就这样，我这个技术架构师兼项目经理、主力程序员就这样荣耀登场了。&lt;/p&gt;&#xD;
&lt;p&gt;正如您的高见，我本敲代码者，很多时候不自觉就追求设计的完美去了，等绕了半天之后，才发现原来自己还是个项目经理，还有开发周期在候着呢，更杯具的是，还得去收回当初信誓旦旦跟老板一起放出的那些卫星。通过这个事情，终于切身的体会到一个问题，如果没有制度上的制约，监督者与执行者又是一家人的话，混乱与腐败就是必然的了（呵呵，和谐社会请勿过度联想）。OK，非技术问题在此就不深入展开了，如果是PLMM，则欢迎来电来函来家，彻夜深入探讨，其他者请绕行。&lt;/p&gt;&#xD;
&lt;p&gt;在这个产品中，有个需求：不同的用户登录后，操作界面必须根据其角色进行自动调配，白话说就是用户登录后，如果其是收银员，那么那就只能操作收银窗口及其只能看到或者使用相关的一些功能窗口的入口菜单或者导航树节点。另外，该产品分为不同的发布版本，有精简版、标准版、超级宇宙无敌奥特曼版等等，那么在这些各种版本的发布中包含的功能窗口和模块是不一样的，也就是说，同一种东西要切成不同部分去兜售。看到这里，您或许已经告诉我该怎么做了：在登录成功后的事件中写代码去隐藏相关菜单、导航树节点、主窗口的图形按钮等入口元素，将不同的模块放在不同的Library项目中，发布的相关版本引用相关程序集即可。得幸，当初在下也是这么想的，但是、但是，依咱哥们的秉性，这种傻大笨粗的搞法实在太对不起架构师这个亮闪闪的头衔和Boss当初那饱含热泪殷切期望的眼神了，再怎么地，也得想个稍微对得起咱名声的搞法，嗯，嗯，那个项目周期先缓缓，容俺想想，很快就好的了&amp;#8230;&lt;/p&gt;&#xD;
&lt;p&gt;彗星撞地球，果然灵光一闪，插件、全面插件化的架构绝对是彻底、一劳永逸解决这个问题的根本性的宇宙无敌之方案！！！而且，它还可以带来很多别的好处&amp;#8230;譬如1、2、3、4&amp;#8230; 我总得先说服自己吧.. 嘿嘿，既然这么多好处，那就赶快搞吧。嗯，嗯，那个项目周期，可以再探讨的嘛，这个东西的价值是非常可观的，而且还可以为今后公司所有的产品服务，虽然现在还不知道其他产品在哪，但公司在迅猛发展总会有的噻&amp;#8230;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;初试&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;既然已经决定要搞，那么怎么个搞法就得先定下来，兵先阀谋还是知道的。做法有二：1、基于SharpDevelop的插件框架来做；2、自己设计开发。&lt;/p&gt;&#xD;
&lt;p&gt;如果采用策略一，首先得把SharpDevelop的核心插件库剥离出来窃为己用，但是必须确保对SharpDevelop有深入的掌控，对其设计思想和架构模式做到了然于胸，以免发生后期无法实现的想法或出现解决不了的Bugs。诚然，要做到如上要求，短期内怕是不太可行，而且有过前些年看其源码的惨痛经历，如今已是心有戚戚焉。&lt;/p&gt;&#xD;
&lt;p&gt;还是采用策略二吧，但首先面临的问题就是，从头搭建一个框架无论是时间成本还是技术风险都是难以预估的，但凡有点良知的兄弟都能看出来，俺要真这么干，就有点利令智昏不知死活了，基本可以拉出去枪毙五分钟。嘿嘿，所幸俺还是能在激动关头保持最后一点理智的，再三权衡，最终决定先做个能满足目前需求的这样一个界面层自动适应功能的类库出来，其他伟大的想法等日后择机再搞吧。&lt;/p&gt;&#xD;
&lt;p&gt;要满足将功能入口点动态挂载到主窗口中去，必须得定义一个配置文件，这个文件起码需要描述挂入的类型（如菜单、导航树、主窗口的桌面快捷图标）、目标窗口的类型、挂载点的显示文本、图标等，不同的角色需要有不同的配置方案，那么可能还要包含一个对挂载配置进行选择的机制。嗯，差不多先就这些了，呵呵，至此俺的想法还是这么纯朴，真为自己骄傲，没有引入其他脱离实际的高调想法进来，一切看起来都在控制之中，不错不错，暗爽一下先。&lt;/p&gt;&#xD;
&lt;p&gt;好了，就从这个配置文件开始吧，有了它，思路就会一步步清晰起来的，顺着这个思路往下理，后面的实现部分就快了。看起来是这个样子：&lt;/p&gt;&lt;pre &gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&#xD;
&amp;lt;configuration&amp;gt;&#xD;
	&amp;lt;configSections&amp;gt;&#xD;
		&amp;lt;section name="themeManager" type="Zongsoft.Applications.Configuration.ThemeManagerSection, Zongsoft.Applications" /&amp;gt;&#xD;
	&amp;lt;/configSections&amp;gt;&#xD;
&#xD;
	&amp;lt;themeManager&amp;gt;&#xD;
		&amp;lt;theme name="" resourceName="" resourceAssembly=""&amp;gt;&#xD;
			&amp;lt;menu name="BaseMenu" style="Menu" generatorType="Zogsoft.Applications.Themes.ThemeMenuElementGenerator, Zongsoft.Applications"&amp;gt;&#xD;
				&amp;lt;menuItem name="" text="" icon="" toolTip="" shortcut="" commandType="Zongsoft.Applications.WinForms.ShowFormCommand, Zongsoft.Applications"&amp;gt;&#xD;
					&amp;lt;properties&amp;gt;&#xD;
						&amp;lt;add name="Command.TargetType" type="System.String" value="Zongsoft.AMS.Basic.FTimeSpan, Zongsoft.AMS" /&amp;gt;&#xD;
						&amp;lt;add name="Command.ShowDialog" type="System.Boolean" value="False" /&amp;gt;&#xD;
						&amp;lt;add name="Command.Singleton" type="System.Boolean" value="True" /&amp;gt;&#xD;
						&amp;lt;add name="Constructor.ModuleName" type="System.String" value="" /&amp;gt;&#xD;
						&amp;lt;add name="Constructor.DefaultDateTimePart" type="Zongsoft.AMS.Common.DateTimePart, Zongsoft.AMS.Common" value="Time" /&amp;gt;&#xD;
						&amp;lt;add name="CustomProperty" type="System.Object" value="" /&amp;gt;&#xD;
					&amp;lt;/properties&amp;gt;&#xD;
				&amp;lt;/menuItem&amp;gt;&#xD;
			&amp;lt;/menu&amp;gt;&#xD;
&#xD;
			&amp;lt;menu name="Navigator" style="Navigator" generatorType="Zogsoft.Applications.Themes.ThemeMenuGenerator, Zongsoft.Applications"&amp;gt;&#xD;
				&amp;lt;menuItem name=""&amp;gt;...&amp;lt;/navigate&amp;gt;&#xD;
			&amp;lt;/menu&amp;gt;&#xD;
		&amp;lt;/theme&amp;gt;&#xD;
	&amp;lt;/themeManager&amp;gt;&#xD;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&#xD;
&lt;p&gt;上述配置文件可包含多个主题，主题下面是具体菜单和菜单项，不同的菜单由style属性指定其对应的是菜单还是导航树抑或别的什么，在点击菜单或者导航树的时候，通过菜单项的扩展属性集里面的Command.TargetType项指定的类型来创建对应的对象，可能不同的目标类型需要使用特定的构造函数签名进行初始化，那么通过名称以&amp;#8220;Constructor&amp;#8221;打头的扩展属性项来指定构造函数的参数定义，当然，如果觉得这些还不够用，可以自定义一个Generator类来解析这些配置内容，将该自定义的Generator类型名称放在菜单元素的generatorType属性中指定即可。需要定义的类，大致如下：&lt;/p&gt;&lt;pre &gt;public abstract class GeneratorBase&#xD;
{&#xD;
	//初始化生成器，必须指定其对应的&#xD;
	protected GeneratorBase(Theme theme)&#xD;
	{&#xD;
		this.Theme = theme;&#xD;
		/* ... more ... */&#xD;
	}&#xD;
&#xD;
	public Theme Theme&#xD;
	{&#xD;
		get;&#xD;
		private set;&#xD;
	}&#xD;
&#xD;
	//根据菜单元素生成对饮的菜单或者树型节点之类的目标对象&#xD;
	public abstract object Generate(MenuElement element);&#xD;
}&#xD;
&#xD;
public class Theme&#xD;
{&#xD;
	//该主题对象对应的&lt;theme&gt;配置元素&#xD;
	private ThemeElement _element;&#xD;
&#xD;
	internal Theme(ThemeManager manager, ThemeElement element)&#xD;
	{&#xD;
		this.Manager = manager;&#xD;
		_element = element;&#xD;
		/* ... more ... */&#xD;
	}&#xD;
&#xD;
	public ThemeManager Manager&#xD;
	{&#xD;
		get;&#xD;
		private set;&#xD;
	}&#xD;
&#xD;
	//表示通过GeneratorBase的生成方法后激发，可以在外部进行其他附加处理&#xD;
	public event EventHandler&amp;lt;ItemGeneratedEventArgs&amp;gt; Generated;&#xD;
&#xD;
	//调用GeneratorBase的Generate方法生成目标对象，并将该目标对象与caller参数指定的容器进行粘合&#xD;
	public object Build(object caller, string menuName);&#xD;
&#xD;
	//对Build方法的复合处理&#xD;
	public object[] BuildAll(object caller);&#xD;
}&#xD;
&#xD;
public class ThemeManager&#xD;
{&#xD;
	//根据配置节创建Theme类，并初始化资源服务&#xD;
	public void Initialize(ThemeManagerSection section);&#xD;
&#xD;
	//根据指定的资源项名称获取对应的资源对象&#xD;
	public object GetResourceObject(string name);&#xD;
&#xD;
	//同上方法的泛型版本&#xD;
	public T GetResourceObject&amp;lt;T&amp;gt;(string name);&#xD;
&#xD;
	//获取主题对象集合&#xD;
	public ThemeCollection Themes&#xD;
	{&#xD;
		get;&#xD;
	}&#xD;
}&lt;/pre&gt;&#xD;
&lt;p&gt;就这么三个核心类，基本可以应付目前这种需求了，代码也比较简单，就不再叽歪了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;插曲&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;.NET社团的老大，就是那个有点微微软的家伙，总喜欢在我们为自己取得一些积累的时候，突然抛一个新玩意出来刺激下我们衰弱的神经，顺带消灭我们那些颇为自得的成绩，而社团内的众多粉丝又都是一帮热衷自残的家伙，于是乎，大家铺天盖日的一番跟风猛跑，杯具的是，俺也是这帮家伙中的积极分子。&lt;/p&gt;&#xD;
&lt;p&gt;就在.NET 3.5发布之际，俺盯上了那个传说中叫作 System.Addin 的美女，不关三七二十八呼啦冲上去就是一阵蹂躏。唉，传说与现实往往是相对的，又或许别人眼中的美女跟自己根本就是阻抗严重不匹配吧，总之，经过俺一番彻底细致的摆弄之后，发现这个东东压根不是俺臆想中的样子，这使得我早已疲惫的心再次惨遭无情痛击。&lt;/p&gt;&#xD;
&lt;p&gt;在 MAF(System.Addin)中，插件与插件宿主之间需要通过严谨的Contract来进行阻抗匹配，宿主与插件内部都有各自的视图用以隔离实现与通讯协定，而各自的视图再通过对应的适配器与之协定进行转换。这个高度繁琐的模型就是为了确保插件与宿主之间阻抗的正确匹配，还可以在不影响宿主或外接程序的情况下更改适配器和协定。想法是好的，设计是糟糕的，在没有亲手写代码去实验的情况下，要想把这么绕的理念整明白，还是有些难度的，为了搞清楚这到底是怎么回事，俺只好先身体力行的按照MSDN上的指引，一步步把Demo重做了一遍，虽然Demo期间我无数次的问候过一些人，但还是咬牙坚持了下来，一个小Demo总共需要7个项目，就算除掉Host之外也还有6个，如果你做完Demo后还能神志清醒的淡定高呼一声&amp;#8220;Microsoft&amp;#8221;的话，那么恭喜你，本年度最佳盖子奖非您莫属。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;一不小心，咱也奔三了，梦想中的插件框架一直萦绕心头已成为挥之不去的梦魇。这期间又做过一些项目，对俺上次做的那个简单的主题类库也进行了一番升级改造，但是，底层设计思想决定了高层结构，胚子太丑再怎么拾辍始终还是装不出美女来，不进行基因变异，是没有出路的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;前戏&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;老天爷突然睡醒，一摆手丢了个机会下来，不偏不倚正好砸在白天没啥鸟事，晚上鸟没啥事的本少爷头上 &amp;#8212;&amp;#8212;嘿嘿，有个哥们找我做个富客户端的企业应用项目。赶紧把俺那套混饭的家伙拾掇拾掇开工干吧，一切按部就班，也没啥叛逆的想法就盼着早点把东西做完交活收钱，然天有不测风云，人有发癫打狂，就在一切顺风顺水的时候，突然地，看着那个主题类库就莫名开始抽经，越看越郁闷，越郁闷就越想废掉它。这次，这个项目时间非常宽松，基本任由着我的性子来，怎么办？要不要搞？到底是要还是要？！呵呵，以前那么多闲淡时间因为没有做项目，就没觉着这个东西还是那么重要，这次切肤之不爽，再不彻底把她整服帖了，以后还是不好混啊，而且MAF这个不靠谱的家伙也让我彻底死心了。&lt;/p&gt;&#xD;
&lt;p&gt;承蒙天意，皇恩浩荡，俺在历经一阵痛苦的抽搐之后，终于痛下决心！某位非著名人士有云：人生的重大事件往往都是短短几分钟内决定的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;把玩Unity&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;根据以往搭建那个主题类库的经验，我首先面临一个对象动态创建和依赖注入的问题，因为各种组件类必须动态创建，这个问题好办，一般使用反射(Reflection)就可以轻松拿下，但是当类之间存在彼此依赖的话，那么这个问题就变得不太好办了，而且在面临多种注入方式&lt;em&gt;（构造子注入、属性注入、方法注入）&lt;/em&gt;，甚至在构造出对象后，还需要自动调用一些非注入性的初始化方法或者响应处理一些事件的话，这个问题就变得相当棘手了。所幸我对Unity这位仁兄略有耳闻，知道他能够帮我处理这些非插件框架核心但却是基本功能的问题，不过对于如何使用Unity与插件框架进行整合，我还没有清晰的思路，更让我抑郁的是，至今还没听说过SharpDevelop或者Eclipse中集成相关IoC容器的做法，我不确定我这个想法的方向是否正确，而且以前从SharpDevelop的源码中也没看到过类似这么复杂的创建或依赖注入的代码。怀疑终归是怀疑，我还是需要一点论证，至少我需要仔细了解下Unity的内部构造，起码也要看看能不能从另外一个角度帮我理清下思路。&lt;/p&gt;&#xD;
&lt;p&gt;先上博客园找了一些介绍Unity的文章做到心中有数，一番风卷残云般的快速阅读，大致理念弄清楚了。再从Unity的官方网站下载最新源码，对照一些朋友写的剖析Unity的文章&lt;em&gt;（看来跟我一样喜欢扒源码的窥窃男不在少数哈）&lt;/em&gt;，一边看源码一边对资料，对着对着发现路子不对，因为这些兄弟写的文章基本是依照老版本写的，本着从高从新的伟大理念，也懒得去找老版源码了，就这么凑合看吧，基本把ObjectBuilder的东西看了一遍，大致意思是明白了，主要是Strategies指使Policies去干活，由Lifetime负责管控对象的生命周期和提供容器，一些细节如定位查找等交由Locator去打理，ObjectBuilder只是个对外的前台小妹。UnityContainer内部把对象创建和管理的工作都交给ObjectBuilder处理，自己专注其他辅助功能，譬如配置管理、注入依赖的关联操作并由此引申出来的一大坨杂七杂八的事项。看到这里，基本也没兴趣深挖下去了，因为跟我想要的插件思想没有关系，看来这位仁兄不能带给我额外的思路，而且，如果一个插件框架需要包含一个这么复杂的构建容器是不是有些本末倒置之嫌，这不符合我历来讲究的精巧优雅的架构原则，嗯，可以把它排除了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;细探Addin&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;锁定SharpDevelop，不把她拿下绝不睡觉！&lt;/p&gt;&#xD;
&lt;p&gt;老套路，还是从她的官方网站(&lt;a title="http://www.icsharpcode.net/opensource/sd/" href="http://www.icsharpcode.net/opensource/sd/" target="_blank"&gt;http://www.icsharpcode.net/opensource/sd/&lt;/a&gt;)下载最新源码，乖乖，现在都3.2版本了，已经长成大姑娘了，嘿嘿~ 文档还是一如既往的精炼，官方论坛的一些零星讨论不能解决我的大问题，只好把那本已经压在床脚多年的《C#软件项目开发全程剖析&amp;#8212;&amp;#8212;全面透视SharpDevelop软件的开发内幕》(&lt;a title="http://www.china-pub.com/13944" href="http://www.china-pub.com/13944" target="_blank"&gt;http://www.china-pub.com/13944&lt;/a&gt;)一书翻出来，在杀死我一些脑细胞之后，除了令我比以前更抑郁外，就是使我更加怀疑自己到底有没有学过中文，这些年说得是不是火星语。&lt;/p&gt;&#xD;
&lt;p&gt;熟练的扒掉她的外套，仔细阅读源码，这次汲取上次的失败，不再从StartUp项目入手而是打开她的AddIn-Scout工具，高瞻远瞩的从整体结构布局入手，一边用该工具查看插件结构，一边对照ICSharpCode.SharpDevelop.addin源文件，一点一点的摸索她的规律，再结合这些年自己断断续续的一些所思所得去推敲她为什么要有一个这样的结构，这些结构究竟是为了解决什么问题，她的核心思想是什么。在深夜里俺不怀好意的死盯她的内部结构，时而跟踪看看类的定义，时而看看对应的Addin文件定义项，时而停下来思考下为什么的问题，终于在自虐了数个不眠之夜、耗光多包&amp;#8216;红色利群&amp;#8217;和槟榔后，被俺想通了几个关键问题，譬如那个非著名的暧昧三角关系以及这些内部构件之间的协同作战问题，同时也想明白了为什么插件架构不需要使用像Unity这样的专业IoC框架来处理构件的创建和依赖注入的问题。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;主题&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;前面调戏了这么久，再不切入主题就该挨埋怨了。感谢各位东西方仙界朋友的保佑，费了九牛二虎之力把那些关键问题想通之后，再不果断下手就不只是挨埋怨那么简单了，让人怀疑能力有问题那才真麻烦呢。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;开搞&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在本文的「初识」部分谈到过我对SharpDevelop的一些不爽之处，除此之外还有个令我一直如鲠在喉的不快，那就是对Codon和Doozer这些东西的命名甚感纠结，虽然SharpDevelop开发者在书中也谈到过这个命名问题，但我还是认为这些名字太过生僻。一个好的命名会让人望文生义，这也是我得到偏执者名号的缘由之一。所以，我慎重决定重新厘清这些庞杂系统的概念一并更新命名。首先附上主要的概念性名字解释（含英文名）：&lt;/p&gt;&#xD;
&lt;ul&gt;&lt;li&gt;插件(Plugin)：该英文单词有Plugin和PlugIn的两种写法，前种写法表专有名词，后种为词组，为了照顾编码时书写的整洁度以及.NET通用的命名规则，而采用Plugin写法。插件是插件框架中的逻辑组织单位，可以对应到一个或多个程序集(Assembly)，每个插件必须对应一个XML格式的插件定义文件(*.plugin)，一个插件由众多构件(Builtin)组成，插件定义文件详细描述该插件内各个构件的组合关系。 &lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;构件(Builtin)：英文Built-in原意为&amp;#8220;内置件、零件&amp;#8221;，在此将该词组进行合并引申为构件、部件之意，这个意思非常符合其在插件框架中的角色定位，该元素完全等同于SharpDevelop中的Codon。构件为插件(Plugin)的组成部分，其与插件的关系就好比人体器官(如心脏、头、四肢)与人体，其不能脱离插件独立存在，也是基本功能的具体载体，众构件(Builtins)必须通过插件定义文件将其发布到插件框架中。 &lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;插件树(PluginTree)：该英文为词组，遵循.NET开发规范对类名、方法名、属性名等一律使用Pascal命名规范，下同。首先必须高调澄清一个事实，插件树并不是对插件进行数据结构定义的概念，虽然我在这个地方也一度陷入SharpDevelop中的泥潭难以自拔。插件树是对构件(Builtin)对象在内存中的一种树型数据结构的定义，之所以要称之为PluginTree而不是&amp;#8220;BuiltinTree&amp;#8221;，那是因为它不只是负责管理某一个插件内的所有构件定义，而是全局唯一的，要负责管理整个运行时所有插件内的构件。 &lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;插件树节点(PluginTreeNode)：顾名思义这个元素描述插件树中的某个节点的数据结构，主要包含两个构成：1、该节点在插件树中所处的路径(Path)；2、该节点对应的构件(Builtin)。一个节点只对应一个构件对象，通过它我们可以在插件树中任意导航。 &lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;构建器(Builder)：注意区分该中文名词与Builtin的中文名中的&amp;#8220;件&amp;#8221;和&amp;#8220;建&amp;#8221;字。该概念大致类似于SharpDevelop中的Doozer，它的唯一功能就是根据插件框架提供给它的构件对象生成真实具体干实事的目标对象。正是因为这个东西的存在，插件框架才能彻底摆脱对庞杂的IoC框架的依赖，因为它非常清楚它要构建的对象是什么。但是，我当初的一个主要疑惑就是当它要构建对象的构造函数参数需要引用插件平台的一些公共服务，譬如当前的登录用户名、或者数据访问服务接口对象，或者该参数还需要引用另外一个插件中的构件对象实例以及这个构件实例中的某个属性值，那么这个构建器如何以一种简单优雅的方式去获得这些依赖对象？再次感谢万能的主，因为插件架构的这种树型数据结构，导致了她天然就有解决这个棘手问题的良方，而且是以一种异常优美简洁的方式来实现的，呵呵，稳住稳住，注意控制好节奏，想想美妙的序曲才刚开始，后面还有高潮部分在等着咱呢。 &lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&#xD;
&lt;p&gt;类型(Type)：该元素是本人在设计该插件框架时思忖许久决定引入的一个新概念，跟我设计数据访问框架一样，我的一个原则就是尽量利用.NET中现有或者业界主流设计思想中的概念，非万不得已才引入额外的设计元素，将易用性和广泛适用性原则始终摆在框架设计的最高级别。该元素是为了解决构建器创建构件对应的目标对象时，需要使用到对一些非插件框架服务以及其他插件所能提供的常量型数据的问题。&lt;strong&gt;该元素只作为构件的子元素出现在插件定义文件中，是对构件目标类型的一种补充描述。&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;好吧，就算可以引入该元素，但我还是要找到能100%说服自己有绝对充分的理由和必要。为什么SharpDevelop中没有包含类似的概念？经过我的一番努力查找源码，发现SharpDevelop这种应用主要是处理开发工具这种需求，在这种应用中基本没有在企业管理软件中一个窗体在构建过程中需要使用一些固定常量的情况，OK，这个理由不够说服力，因为我无法从根本上枚举出所有的需求情景，那么理由二：对于这种简单常量的初始化参数如果也使用构建器中描述的那种依赖注入方式，明显有高射炮打蚊子之嫌，而且对于插件的实现者而言，明显会增加不必要的开发量，更严重的是，它会破坏我一直提倡的简洁优雅的设计和使用理念。呵呵，这个理由足够充分了罢，而且增加这个概念之后并不会给系统带来额外的复杂性和臃肿感，无论对于普通插件开发人员还是框架实现者本人都不会造成额外的工作量，相反它只是简化插件开发的工作并使之更易于理解和配置。 &lt;/p&gt;&lt;/li&gt;&lt;li&gt;类型别名(TypeAlias)：在构件定义过程中，经常需要指定一些没有挂入插件框架的类型(如：System.Windows.Forms.Form, System.Windows.Forms)，如果不幸这些类型又需要频繁使用的话，那么在每个地方都重写一遍，无疑是劳民伤财的，与朝廷提倡的建设低碳节能型社会是背道而驰滴，是不与时俱进滴，是没有充分理解带三个表滴，是反XXX&amp;#8230;. &lt;em&gt;(汗)&lt;/em&gt; 所以，我就让这个概念华丽登场了，应该不会有不知时务者反对吧，呵呵，河蟹好河蟹好。 &lt;br /&gt;&lt;/li&gt;&lt;li&gt;解析器(Parser)：这个对应到SharpDevelop中的解析器类，但是处理手法上与SharpDevelop不同，我把这部分的功能单独出来别于普通构件，让其专司解析之职。它只有一个重要职责：负责将插件定义文件中的某些构件的设置属性的文本解析成它真正需要的东西。听来有点绕口，举例：假如某菜单项构件在插件定义文件中的定义如： &lt;pre &gt;&amp;lt;menuItem name="Print" type="MenuItem"&#xD;
			text="{res:PrintLabel}"&#xD;
			icon="{res:Icons.16x16.Print}"&#xD;
			shortcut="Control|P"&#xD;
			command="/Workspace/Commands/PrintCommand" /&amp;gt;&lt;/pre&gt;看到text和icon特性&lt;em&gt;(XML元素的Attribute)&lt;/em&gt;中的那些{res:xxxxxxx}字符么咯？Good，恭喜你答对了，Parser就是负责解析这些字符串的家伙，它会返回一些别的什么玩意给构件(Builtin)对象，其中的res:部分就是指定用哪个解析器来解析冒号(:)后面的内容。 &lt;/li&gt;&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;以上较为详细的介绍了本插件框架中涉及的几个重要核心概念，需要特别指出的是，所有这些元素都是生而平等的，他们在插件环境中都占有同等地位的位置，虽然概念和职责各不相同，但都是为人民服务，身为它们的God，俺是绝对不允许这些家伙中有歧视存在，Never！每个插件结构都可以通过插件树查找到这些元素，并随时为您服务。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;不妙，有情况&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在此，还是忍不住要批评一下SharpDevelop这位国际友人，虽然她如此无私的将她的Body任由我多番蹂躏，也曾陪伴我走过很多个落寞的夜晚，曾让我时而抑郁、时而激昂，时而欢欣、时而捶胸顿足，但不管怎样她都始终一如既往的陪伴着我欢乐悲喜的一路成长。&lt;/p&gt;&#xD;
&lt;p&gt;不幸在一些主要类中看到这样的代码：&lt;/p&gt;&lt;pre &gt;static AddInTree()&#xD;
{&#xD;
	doozers.Add("Class", new ClassDoozer());&#xD;
	doozers.Add("FileFilter", new FileFilterDoozer());&#xD;
	doozers.Add("String", new StringDoozer());&#xD;
	doozers.Add("Icon", new IconDoozer());&#xD;
	doozers.Add("MenuItem", new MenuItemDoozer());&#xD;
	doozers.Add("ToolbarItem", new ToolbarItemDoozer());&#xD;
	doozers.Add("Include", new IncludeDoozer());&#xD;
			&#xD;
	conditionEvaluators.Add("Compare", new CompareConditionEvaluator());&#xD;
	conditionEvaluators.Add("Ownerstate", new OwnerStateConditionEvaluator());&#xD;
			&#xD;
	ApplicationStateInfoService.RegisterStateGetter("Installed 3rd party AddIns", GetInstalledThirdPartyAddInsListAsString);&#xD;
}&lt;/pre&gt;&lt;pre &gt;&lt;/pre&gt;&#xD;
&lt;p&gt;这披露了一个性质非常严重的事件，这个 AddInTree 类是SharpDevelop插件框架的核心类，在其静态构造函数中硬编码对某些特殊Doozer和ConditionEvaluator进行初始化动作，这本身就有悖于所有插件结构均一视同仁的插件化理念，正是因为这些少数的特殊化分子导致了后面的插件应用有样学样的一通胡搞。这个问题，我必须得严肃反应一下，虽然我不否认这些个Doozer在整个框架中的重要性，但是就算其功能再重要也不能脱离插件平台的法则约束，所谓法则就是我上面提到的&amp;#8220;&lt;strong&gt;所有插件结构在平台中都具有生而平等的不容侵犯的插件权&lt;/strong&gt;&amp;#8221;，就算某个元素告诉我他掌管着诸多构件的生杀大权，那依然得遵守&amp;#8216;天赋插权&amp;#8217;的法则，总统都还得轮着坐呢。难怪我先前在Addin-Scout工具中怎么都不能在插件树中找到这些Doozer的位置，感情都跑到这里潜规则来了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;再来围观一下 WorkbenchSingleton 类中的 InitializeWorkbench() 方法&lt;/p&gt;&lt;pre &gt;public static void InitializeWorkbench(IWorkbench workbench, IWorkbenchLayout layout)&#xD;
{&#xD;
	WorkbenchSingleton.workbench = workbench;&#xD;
&#xD;
	DisplayBindingService.InitializeService();&#xD;
	LayoutConfiguration.LoadLayoutConfiguration();&#xD;
	FileService.InitializeService();&#xD;
	StatusBarService.Initialize();&#xD;
	DomHostCallback.Register(); // must be called after StatusBarService.Initialize()&#xD;
	ParserService.InitializeParserService();&#xD;
	Bookmarks.BookmarkManager.Initialize();&#xD;
	Project.CustomToolsService.Initialize();&#xD;
	Project.BuildModifiedProjectsOnlyService.Initialize();&#xD;
&#xD;
	/* ... more ... */&#xD;
}&lt;/pre&gt;&#xD;
&lt;p&gt;还有 CoreStartup 类中的 StartCoreServices() 方法&lt;/p&gt;&lt;pre &gt;public void StartCoreServices()&#xD;
{&#xD;
	if (configDirectory == null)&#xD;
		configDirectory = Path.Combine(&#xD;
                            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),&#xD;
                            applicationName);&#xD;
&#xD;
	PropertyService.InitializeService(configDirectory,&#xD;
			    dataDirectory ?? Path.Combine(FileUtility.ApplicationRootPath, "data"),&#xD;
                            propertiesName);&#xD;
&#xD;
	PropertyService.Load();&#xD;
&#xD;
	ResourceService.InitializeService(FileUtility.Combine(PropertyService.DataDirectory, "resources"));&#xD;
	StringParser.Properties["AppName"] = applicationName;&#xD;
}&lt;/pre&gt;&#xD;
&lt;p&gt;这些特殊分子的榜样力量由此可见一番，其他方面的影响就不一而足了。整个事件给我的感受就有如：当酣畅淋漓正准备放开拳脚大干一番的时候，突然发现某种介质上出现了个洞洞，大煞风景之事，轻者造成一次机体伤害，严重的话，嘿嘿，为此而因噎废食就搞大了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;高潮&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;主题切入这么久了，按理也应该到大家期盼已久的高潮部分了，但是很遗憾，不是每次都能有的，虽然我也很想在这篇文章中，把我设计的插件定义文件作为高潮的产物奉献给大家。无奈，身心俱惫，已经连续苦熬了两个通宵，就俺这个年纪而言，已实属不易。&lt;/p&gt;&#xD;
&lt;p&gt;当自己真正开始插件框架的开发后，里面非常多的细节问题开始逐一浮现，然本文无法一一介绍到，但是，挑战总与成就感结伴同行，上帝与魔鬼将伴随我此后一段相当长的日子，我想这次真的会坚持下去，起码我已能隐约感受到黎明时的温暖。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;尾声&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;与日方长，不争一朝一夕，有意者请恕半老不小生不道德的先撤了，后会无期&amp;#8230;&amp;#8230; bye-bye&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&#xD;
&lt;div style="padding-bottom: 10px; background-color: #ffffe0; margin: 30px 20px 20px; padding-left: 10px; padding-right: 10px; padding-top: 10px"&gt;作者：钟峰(Popeye Zhong)目前是 &lt;a href="http://www.sz-accp.net/" target="_blank"&gt;北大青鸟（深圳中青）培训中心&lt;/a&gt; 的ACCP讲师，负责讲授.NET和SQL数据库开发课程。他曾经使用 C 语言做过图形程序设计，在相当长的一段时期内从事 COM/COM+ 组件的开发和设计工作，并且短暂的做过 Lotus/Notes 和 Dialogic 语音卡程序的开发，从2003年初开始使用.NET这个充满趣味和挑战的开发平台，还领导过.NET平台下的 Windows Mobile 几个项目的开发，对WinForm和WebForm均比较熟悉。感兴趣的除了企业应用架构设计、组件开发、安全、图像处理外还对汽车和枪械模型、边境牧羊犬有浓厚的兴趣。如果希望与他联系，可访问 &lt;a href="http://www.cnblogs.com/sw515" target="_blank"&gt;http://www.cnblogs.com/sw515&lt;/a&gt; 或者Email Zongsoft # gmail.com &lt;em&gt;(将#换成@)&lt;/em&gt;。 &lt;/div&gt;&lt;img src="http://www.cnblogs.com/SW515/aggbug/1718262.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SW515/archive/2010/04/23/1718262.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SW515/archive/2007/08/24/868912.html</id><title type="text">恢复Ico图标文件在资源管理器中的显示</title><summary type="text">在安装了某些看图或者图片编辑软件后，可能会导致ico图标、cur/ani光标文件在资源管理器中显示的不再是其本身的图片内容，而是某个特定的图标，这对于直接查看图标文件很不方便，如果要恢复其默认的可见方式，可在命令窗口[ cmd ]中使用如下命令：assoc .ico=icofileassoc .cur=curfileassoc .ani=anifile</summary><published>2007-08-24T13:58:00Z</published><updated>2007-08-24T13:58:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2007/08/24/868912.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2007/08/24/868912.html"/></entry><entry><id>http://www.cnblogs.com/SW515/archive/2006/10/25/539489.html</id><title type="text">深入剖析 ASP.NET 1.x 中 Forms 身份验证(1)</title><summary type="text">前言今年六月份做的一个视频讲座，只做了上半部分的理论和代码解析部分，本打算还有下半部分的范例演示的，但因为时间和惰性，一直拖到现在也没把下半部分都做完。　　最近，因为刚好讲到ASP.NET 1.1中FormAuthentication部分的课程，有些内容在课堂上不宜深入讨论，所以，索性将这个只讲到一半的东西再拿出来发给学员。相信大家看了这上部分的视频演讲后，自己再动手完成代码应该不会有什么大问题了...</summary><published>2006-10-25T06:03:00Z</published><updated>2006-10-25T06:03:00Z</updated><author><name>钟少</name><uri>http://www.cnblogs.com/SW515/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SW515/archive/2006/10/25/539489.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SW515/archive/2006/10/25/539489.html"/></entry></feed>
