<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://community.icburner.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang=""><title type="html">Web开发技术</title><subtitle type="html" /><id>http://community.icburner.com/blogs/webdev/atom.aspx</id><link rel="alternate" type="text/html" href="http://community.icburner.com/blogs/webdev/default.aspx" /><link rel="self" type="application/atom+xml" href="http://community.icburner.com/blogs/webdev/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.40407.4157">Community Server</generator><updated>2009-05-26T19:12:53Z</updated><entry><title>Managing Entity Framework ObjectContext lifespan and scope in n-layered ASP.NET applications</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/06/01/managing-entity-framework-objectcontext-lifespan-and-scope-in-n-layered-asp-net-applications.aspx" /><id>/blogs/webdev/archive/2009/06/01/managing-entity-framework-objectcontext-lifespan-and-scope-in-n-layered-asp-net-applications.aspx</id><published>2009-06-01T10:50:24Z</published><updated>2009-06-01T10:50:24Z</updated><content type="html">&lt;p&gt;&lt;a href="http://dotnetslackers.com/code/NorthwindSampleApplication.zip"&gt;Download Sample Code&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Introduction&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Since the introduction of the ADO.NET Entity Framework, I&amp;#39;ve been looking for ways on how to incorporate this &lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image001_5F00_3.gif"&gt;new technology&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="clip_image001" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image001_5F00_thumb.gif" width="14" height="14" /&gt;&lt;/a&gt; in a typical n- layered ASP.NET application. I&amp;#39;ve started off by replacing the traditional - mostly handwritten - Data Access classes (DAL) with a database generated Entity Data Model (EDM). This offers some great benefits, for example by speeding up development time, and reducing the number of bugs in the DAL. &lt;/p&gt;  &lt;p&gt;The middle layer &amp;#8211; or Business Logic Layer (BLL) as I like to call it - classes remain effectively the same as in the .NET 2.0 days. The only difference is in how they use the Data Access objects, which needless to say reside in the Data Access Layer (DAL). Instead of referencing their counterpart DAL classes (for example the ProductBLL class methods may call data access methods in the ProductDAL class), the BLL classes now use an instance of an ObjectContext for their data access purposes. In this role, the ObjectContext class replaces the more traditional DAL classes.&lt;/p&gt;  &lt;p&gt;Up till now everything I&amp;#39;ve described has been pretty straightforward. However, some problems may arise when you start to think about how to use an ObjectContext in a scenario where you have multiple BLL classes, and you want to be able to exchange &lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image001_5B00_1_5D00_.gif"&gt;business objects&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="clip_image001[1]" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image001_5B00_1_5D005F00_thumb.gif" width="14" height="14" /&gt;&lt;/a&gt; (i.e. domain entities) between instances of those classes. Since all changes are tracked by an ObjectContext (instead of by the objects themselves), it&amp;#39;s not always easy to &amp;quot;mix&amp;quot; objects that originate from different ObjectContext instances. However, there are several ways to share ObjectContext instances between BLL classes within the BLL. Each with its own advantages and disadvantages. &lt;/p&gt;  &lt;p&gt;One way to do it for example, is to use a single ObjectContext for each business transaction (in a Unit of Work pattern). Another way to do it, is by globally sharing a single ObjectContext instance between all BLL classes. Each of these methods will be discussed in more detail later in this article.&lt;/p&gt;  &lt;p&gt;&lt;a name="the-problems-of-working-with-____multipl"&gt;&lt;/a&gt;&lt;b&gt;The problems of working with multiple ObjectContext instances&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Like I mentioned in the introduction, working with multiple instances of an ObjectContext class simultaneously can be a bit troublesome. In the Entity Framework changes are tracked by an ObjectContext instance, instead of by the business objects/entities themselves. To be able to define and save a relationship between objects that originated from different ObjectContext instances, you would first have to &amp;#8220;detach&amp;#8221; an entity (i.e. business object) from its originating ObjectContext instance, and then &amp;#8220;attach&amp;#8221; it to the ObjectContext of the other entity. For example:&lt;/p&gt;  &lt;p&gt;NorthwindObjectContext objectContext1 = new NorthwindObjectContext();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Categories category = objectContext1.Categories&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .FirstOrDefault(c =&amp;gt; c.CategoryID == 1);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;NorthwindObjectContext objectContext2 = new NorthwindObjectContext();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Products product = objectContext2.Products&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .FirstOrDefault(p =&amp;gt; p.ProductID == 1);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;/* Detach from originating ObjectContext: */&lt;/p&gt;  &lt;p&gt;objectContext1.Detach(category);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;/* Attach to the other ObjectContext: */&lt;/p&gt;  &lt;p&gt;objectContext2.Attach(category);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;/* Define a relationship between the category and product objects: */&lt;/p&gt;  &lt;p&gt;product.Categories = category;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;objectContext2.SaveChanges();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Moreover, the Detach() method only detaches the object that was supplied as an argument. It does not automatically detach related objects. &lt;/p&gt;  &lt;p&gt;The code sample above is just a demonstration of the concept of &amp;#8220;detaching&amp;#8221; and &amp;#8220;attaching&amp;#8221; entities. Obviously, I could have just loaded both the category and product objects from the same ObjectContext instance, and thus avoiding any problems whatsoever. This is also true for projects that query an Entity Data Model (EDM) directly in their Presentation Layer (in for example the code behind files). However, in my projects &amp;#8211; no matter how small &amp;#8211; I always use a middle layer (BLL) to store my LINQ-to-Entities queries and business logic. It&amp;#8217;s my preferred way of working, because it promotes maintainability and extensibility. It also allows me to unit test my code.&lt;/p&gt;  &lt;p&gt;Working with a middle layer (BLL) also means that you will be dealing with multiple BLL classes. There will probably be a separate BLL class for each of your business objects (i.e. domain entities). For example if we look at our code sample above, we might have created a ProductsBLL and a CategoriesBLL class. Business objects returned from instances of those classes, may define relationships with one another. Persisting these relationships will result in an exception being raised if both of the BLL classes use different ObjectContext instances. So we have to either make sure that both of the BLL classes use the same ObjectContext instance, or that we have &amp;#8220;manually&amp;#8221; tied the objects who defined the relationship to the same ObjectContext instance.&lt;/p&gt;  &lt;p&gt;Writing code for attaching and detaching entities in a n-layered ASP.NET application can sometimes become a bit cumbersome, and moreover it&amp;#8217;s often unnecessary. There are several good ways of sharing your ObjectContext instances among your BLL classes. In the sections that follow, I will discuss a few of these ways in detail. In the sample code that I have provided, I&amp;#8217;ve also included a small generic framework for managing ObjectContext instantiation in your middle layer classes.&lt;/p&gt;  &lt;p&gt;&lt;a name="one-shared-static-objectcontext"&gt;&lt;/a&gt;&lt;b&gt;One shared static ObjectContext&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Lets first start off with a way of sharing an ObjectContext that isn&amp;#8217;t suitable for ASP.NET webapplications. I&amp;#8217;ve read a lot of forum posts on the internet, in which developers tend to use an ObjectContext as a static class member. In this way the ObjectContext can be globally shared between all classes that use it. It offers some great flexibility, since all business objects/entities in the application originate from the same ObjectContext instance. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;Listing 1: Using a static ObjectContext &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;1. private static NorthwindObjectContext _objectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;2. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;3. /// Returns a shared static NorthwindObjectContext instance. &lt;/p&gt;  &lt;p&gt;4. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;5. public NorthwindObjectContext ObjectContext&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;6. {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;7. get&lt;/p&gt;  &lt;p&gt;8.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;9. if (_objectContext == null)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;10.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _objectContext = new NorthwindObjectContext();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;11. return _objectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;12.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;13. }&amp;#160; .&lt;/p&gt;  &lt;p&gt;However, you shouldn&amp;#8217;t use a static ObjectContext in an ASP.NET application, since static members have a lifespan beyond that of a single HTTP request. They&amp;#8217;re actually bound to the lifespan of the AppDomain, which might be minutes or hours. In fact, static class members in ASP.NET are even shared between multiple threads and users of the application. Using the same ObjectContext instance from within multiple threads simultaneously can cause serious problems.&lt;/p&gt;  &lt;p&gt;It&amp;#8217;s also generally accepted that ObjectContext instances should have a short lifespan, so keeping an ObjectContext around for minutes or even hours is probably not a good practice. But if you&amp;#8217;re looking for the flexibility that is provided using a static ObjectContext, then have a look at the solution that is presented in the next section.&lt;/p&gt;  &lt;p&gt;&lt;a name="one-shared-objectcontext-instance-per-__"&gt;&lt;/a&gt;&lt;b&gt;One shared ObjectContext instance per HTTP request&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Since sharing an ObjectContext as a static member in an ASP.NET application is a no-go, we have to find some other way to achieve similar flexibility. To do this we have to somehow store an ObjectContext instance in a central place for the lifespan of one - and only one - HTTP request. This is where the HttpContext.Current object comes into place. &lt;/p&gt;  &lt;p&gt;The Items property of the HttpContext.Current object is a Hashtable for storing objects on a per-request basis. All of your BLL (middle layer) classes have access to this property, so this is a place in which we can store an ObjectContext instance, and then share it between all instances of those classes. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;Listing 2: Using the HttpContext.Current.Items property &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;1. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;2. /// Returns a shared ObjectContext instance. &lt;/p&gt;  &lt;p&gt;3. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;4. public NorthwindObjectContext ObjectContext&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;5. {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;6. get&lt;/p&gt;  &lt;p&gt;7.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;8. string ocKey = &amp;quot;ocm_&amp;quot; + HttpContext.Current.GetHashCode().ToString(&amp;quot;x&amp;quot;);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;9. if (!HttpContext.Current.Items.Contains(ocKey))&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;10.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; HttpContext.Current.Items.Add(ocKey, new NorthwindObjectContext());&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;11. return HttpContext.Current.Items[ocKey] as NorthwindObjectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;12.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;13. }&amp;#160; &lt;/p&gt;  &lt;p&gt;It&amp;#8217;s a good practice to use a &amp;#8220;Lazy Load&amp;#8221; pattern in this scenario, so that we only create a new ObjectContext instance when we actually need one.&lt;/p&gt;  &lt;p&gt;By globally sharing an ObjectContext instance between classes on a per-request basis, you&amp;#8217;ll make sure that every business object in your ASP.NET webapplication originates from the same ObjectContext instance. In this way, you won&amp;#8217;t have to worry about which object is being tracked by which ObjectContext, and you can easily exchange business objects (i.e. entities) between all of your BLL classes. Since the ObjectContext instance has the lifespan of only one HTTP request, it&amp;#8217;s also relatively short lived.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Note: &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Be wary of any asynchronous operations that may occur within your ASP.NET application, when using a globally shared ObjectContext instance. Two or more threads simultaneously trying to update data using the same ObjectContext instance can cause serious problems.&lt;/p&gt;  &lt;p&gt;&lt;a name="one-objectcontext-instance-per-business-"&gt;&lt;/a&gt;&lt;b&gt;One ObjectContext instance per business transaction&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;This is the last method of managing an ObjectContext lifespan that I&amp;#8217;ll be discussing in this article. Using this method we will be creating and using one instance of an ObjectContext class within the scope of a business transaction. After the business transaction is complete, we will save all changes to the underlying data store and then dispose the ObjectContext instance.&lt;/p&gt;  &lt;p&gt;By a business transaction I mean a series of operations that atomically belong together. For example: in a webshop application, if we want to store an order in our system, we would first have to create an Order object. Next we would convert the contents of the shopping cart into Orderline objects. These Orderline objects would then have to be added to the Order object. Only after these steps are complete, we can safely store the complete Order object to the database. By using the Entity Framework in such business transactions, changes should be tracked by one single instance of an ObjectContext class. Doing so we are actually applying the &amp;#8220;Unit of Work&amp;#8221; pattern. &lt;/p&gt;  &lt;p&gt;Sharing an ObjectContext within the scope of a business transaction is a trivial task in an ASP.NET application that doesn&amp;#8217;t make use of BLL classes. However, in applications that do have a middle layer things become a little bit harder. We need to somehow &amp;#8220;connect&amp;#8221; the BLL instances within the scope, so they can all use the same ObjectContext instance. This is best done using some sort of helper object, which would contain the ObjectContext instance, and thus defining the scope. We could then for example create an &amp;#8220;AddToScope&amp;#8221; method on the helper object, which would be responsible for placing the BLL instances into scope. However, there is a more elegant and transparent construction possible. By mimicking part of the behavior of the .NET Framework&amp;#8217;s TransactionScope class, we could make our BLL classes self-aware of the scope they currently belong to. &lt;/p&gt;  &lt;p&gt;In the sample code below, an instance of the custom UnitOfWorkScope class in conjunction with a (C#) &amp;#8220;using&amp;#8221; statement is responsible for defining the ObjectContext scope. All BLL instances created within scope can automatically detect it, and therefore use the same ObjectContext instance. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;Listing 3: Defining the scope of a business transaction &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;1. /* Create a new ObjectContext scope, in which all BLL (middle layer) objects share &lt;/p&gt;  &lt;p&gt;2.&amp;#160; * the same ObjectContext instance: */&lt;/p&gt;  &lt;p&gt;3. using (new UnitOfWorkScope(true)) /* &amp;quot;true&amp;quot; flag indicates that all changes &lt;/p&gt;  &lt;p&gt;4.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; * should be saved at the end of the scope. */&lt;/p&gt;  &lt;p&gt;5. {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;6. /* The OrderBLL class can automatically detect the current scope: */&lt;/p&gt;  &lt;p&gt;7.&amp;#160;&amp;#160;&amp;#160;&amp;#160; OrderBLL orderBLL = new OrderBLL();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;8. /* The OrderlineBLL class can automatically detect the current scope: */&lt;/p&gt;  &lt;p&gt;9.&amp;#160;&amp;#160;&amp;#160;&amp;#160; OrderlineBLL orderlineBLL = new OrderlineBLL();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;10. /* The ProductBLL class can automatically detect the current scope: */&lt;/p&gt;  &lt;p&gt;11.&amp;#160;&amp;#160;&amp;#160;&amp;#160; ProductBLL productBLL = new ProductBLL();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;12. /* Create a new order: */&lt;/p&gt;  &lt;p&gt;13.&amp;#160;&amp;#160;&amp;#160;&amp;#160; Order newOrder = new Order();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;14.&amp;#160;&amp;#160;&amp;#160;&amp;#160; newOrder.FirstName = &amp;quot;Jordan&amp;quot;;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;15.&amp;#160;&amp;#160;&amp;#160;&amp;#160; newOrder.LastName = &amp;quot;van Gogh&amp;quot;;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;16. // .. add more order properties here ... &lt;/p&gt;  &lt;p&gt;17. /* Make sure the newOrder object will be added to the data store: */&lt;/p&gt;  &lt;p&gt;18.&amp;#160;&amp;#160;&amp;#160;&amp;#160; orderBLL.Add(newOrder);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;19. /* Convert the ShoppingCartItem objects into Orderline objects: */&lt;/p&gt;  &lt;p&gt;20. foreach (ShoppingCartItem cartItem in _shoppingCart.Items)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;21.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;22.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Orderline newLine = new Orderline();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;23. /* Retrieve a Product object based on its PK: */&lt;/p&gt;  &lt;p&gt;24.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Product product = productBLL.GetProductByID( cartItem.ProductID );&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;25. /* We should be able to define a relationship between the&amp;#160; &lt;/p&gt;  &lt;p&gt;26.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; * newLine object and the product object since we are currently&amp;#160; &lt;/p&gt;  &lt;p&gt;27.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; * in a &amp;quot;Unit of Work&amp;quot; scope, in which both orderlineBLL and&amp;#160; &lt;/p&gt;  &lt;p&gt;28.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; * productBLL objects share the same ObjectContext instance: */&lt;/p&gt;  &lt;p&gt;29.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; newLine.Product = product;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;30.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; newLine.Quantity = cartItem.Quantity;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;31. /* Make sure the orderline object will be added to the data store: */&lt;/p&gt;  &lt;p&gt;32.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; orderlineBLL.Add(newLine);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;33. /* Define a relationship between the newLine and the newOrder objects: */&lt;/p&gt;  &lt;p&gt;34.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; newOrder.Orderlines.Add(newLine);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;35.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;36. } /* End of scope. The newOrder object and it&amp;#39;s Orderline objects will&amp;#160; &lt;/p&gt;  &lt;p&gt;37.&amp;#160;&amp;#160;&amp;#160; * now be persisted to the underlying data store. */&lt;/p&gt;  &lt;p&gt;After studying the code sample above, those who aren&amp;#8217;t familiar with the TransactionScope class may be wondering how the BLL objects can automatically detect the current scope, just by placing them in a &amp;#8220;using&amp;#8221; construct. Well, this is actually achieved by using a thread static class member. Values of thread static class members are only bound to the current thread, instead of the entire application as is the case with normal static members. Besides their scope, they act in the same way as normal static members. In .NET we can make a static class member thread static by adding a [ThreadStatic] attribute to it.&lt;/p&gt;  &lt;p&gt;The UnitOfWorkScope class encapsulates an ObjectContext instance. By setting the value of a thread static member to a UnitOfWorkScope instance, we have a way of sharing its encapsulated ObjectContext among our BLL objects within the current thread. It&amp;#8217;s almost similar to sharing and using a global static ObjectContext, except this time it&amp;#8217;s only being shared within the current thread.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Listing 4: The UnitOfWorkScope class implementation &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;1. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;2. /// Defines a scope wherein only one ObjectContext instance is created,&amp;#160; &lt;/p&gt;  &lt;p&gt;3. /// and shared by all of those who use it. Instances of this class are&amp;#160; &lt;/p&gt;  &lt;p&gt;4. /// supposed to be used in a using() statement. &lt;/p&gt;  &lt;p&gt;5. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;6. public sealed class UnitOfWorkScope : IDisposable&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;7. {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;8.&amp;#160;&amp;#160;&amp;#160;&amp;#160; [ThreadStatic]&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;9. private static UnitOfWorkScope _currentScope;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;10. private NorthwindObjectContext _objectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;11. private bool _isDisposed, _saveAllChangesAtEndOfScope;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;12. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;13. /// Gets or sets a boolean value that indicates whether to automatically save&amp;#160; &lt;/p&gt;  &lt;p&gt;14. /// all object changes at end of the scope. &lt;/p&gt;  &lt;p&gt;15. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;16. public bool SaveAllChangesAtEndOfScope&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;17.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;18. get { return _saveAllChangesAtEndOfScope; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;19. set { _saveAllChangesAtEndOfScope = value; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;20.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;21. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;22. /// Returns a reference to the NorthwindObjectContext that is created&amp;#160; &lt;/p&gt;  &lt;p&gt;23. /// for the current scope. If no scope currently exists, null is returned. &lt;/p&gt;  &lt;p&gt;24. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;25. internal static NorthwindObjectContext CurrentObjectContext&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;26.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;27. get { return _currentScope != null ? _currentScope._objectContext : null; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;28.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;29. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;30. /// Default constructor. Object changes are not automatically saved&amp;#160; &lt;/p&gt;  &lt;p&gt;31. /// at the end of the scope. &lt;/p&gt;  &lt;p&gt;32. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;33. public UnitOfWorkScope()&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;34.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : this(false)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;35.&amp;#160;&amp;#160;&amp;#160;&amp;#160; { }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;36. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;37. /// Parameterized constructor. &lt;/p&gt;  &lt;p&gt;38. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;39. /// &amp;lt;param name=&amp;quot;saveAllChangesAtEndOfScope&amp;quot;&amp;gt; &lt;/p&gt;  &lt;p&gt;40. /// A boolean value that indicates whether to automatically save&amp;#160; &lt;/p&gt;  &lt;p&gt;41. /// all object changes at end of the scope. &lt;/p&gt;  &lt;p&gt;42. /// &amp;lt;/param&amp;gt; &lt;/p&gt;  &lt;p&gt;43. public UnitOfWorkScope(bool saveAllChangesAtEndOfScope)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;44.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;45. if (_currentScope != null &amp;amp;&amp;amp; !_currentScope._isDisposed)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;46. throw new InvalidOperationException(&amp;quot;ObjectContextScope instances &amp;quot; +&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;47. &amp;quot;cannot be nested.&amp;quot;);&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;48.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _saveAllChangesAtEndOfScope = saveAllChangesAtEndOfScope;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;49. /* Create a new ObjectContext instance: */&lt;/p&gt;  &lt;p&gt;50.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _objectContext = new NorthwindObjectContext();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;51.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _isDisposed = false;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;52.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Thread.BeginThreadAffinity();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;53. /* Set the current scope to this UnitOfWorkScope object: */&lt;/p&gt;  &lt;p&gt;54.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _currentScope = this;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;55.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;56. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;57. /// Called on the end of the scope. Disposes the NorthwindObjectContext. &lt;/p&gt;  &lt;p&gt;58. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;59. public void Dispose()&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;60.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;61. if (!_isDisposed)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;62.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;63. /* End of scope, so clear the thread static&amp;#160; &lt;/p&gt;  &lt;p&gt;64.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; * _currentScope member: */&lt;/p&gt;  &lt;p&gt;65.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _currentScope = null;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;66.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Thread.EndThreadAffinity();&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;67. if (_saveAllChangesAtEndOfScope)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;68.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _objectContext.SaveChanges();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;69. /* Dispose the scoped ObjectContext instance: */&lt;/p&gt;  &lt;p&gt;70.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _objectContext.Dispose();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;71.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _isDisposed = true;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;72.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;73.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;74. }&amp;#160; &lt;/p&gt;  &lt;p&gt;The UnitOfWorkScope class should only be used in a &amp;#8220;using&amp;#8221; construct. At the start of the construct a new UnitOfWorkScope instance is created. The constructor of this class creates a new ObjectContext instance. This ObjectContext is then shared and used by other BLL objects within the &amp;#8220;using&amp;#8221; construct. At the end of the construct the Dispose method of the UnitOfWorkScope object is automatically called, which in turn disposes the encapsulated ObjectContext instance. &lt;/p&gt;  &lt;p&gt;In our BLL classes we can use the internal static CurrentObjectContext property to get a reference of the ObjectContext instance that&amp;#8217;s bound the current scope. We could for example define a ObjectContext property within these classes, as in the code sample below:&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Listing 5: Using the CurrentObjectContext property of the UnitOfWorkScope class &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;1. private NorthwindObjectContext _objectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;2. /// &amp;lt;summary&amp;gt; &lt;/p&gt;  &lt;p&gt;3. /// Returns the ObjectContext instance that belongs to the&amp;#160; &lt;/p&gt;  &lt;p&gt;4. /// current UnitOfWorkScope. If currently no UnitOfWorkScope &lt;/p&gt;  &lt;p&gt;5. /// exists, a local instance of the NorthwindObjectContext class &lt;/p&gt;  &lt;p&gt;6. /// is returned. &lt;/p&gt;  &lt;p&gt;7. /// &amp;lt;/summary&amp;gt; &lt;/p&gt;  &lt;p&gt;8. protected NorthwindObjectContext ObjectContext&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;9. {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;10. get&lt;/p&gt;  &lt;p&gt;11.&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;12. if (UnitOfWorkScope.CurrentObjectContext != null)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;13. return UnitOfWorkScope.CurrentObjectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;14. else&lt;/p&gt;  &lt;p&gt;15.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;16. if (_objectContext == null)&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;17.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _objectContext = new NorthwindObjectContext();&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;18. return _objectContext;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;19.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;20.&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;21. }&amp;#160; &lt;/p&gt;  &lt;p&gt;Using one &amp;#8220;fresh&amp;#8221; ObjectContext instance per business transaction, is generally considered to be a good practice. And by using the techniques I demonstrated in this section, you can also make sure that it&amp;#8217;s properly disposed when it&amp;#8217;s no longer needed. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;Note: &lt;/b&gt;&lt;/p&gt;  &lt;p&gt;Using thread static class members in a wider scope than in the specified &amp;#8220;using&amp;#8221; construct can result in unpredictable behavior. This is because ASP.NET threads might be re-used, and thus if there are any leftover thread static values, they might also be unknowingly used again.&lt;/p&gt;  &lt;p&gt;&lt;a name="sample-application"&gt;&lt;/a&gt;&lt;b&gt;Sample Application&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;To demonstrate the techniques that I&amp;#8217;ve described in this article I&amp;#39;ve created a small sample application, based on a part of the Northwind database. It also includes a small ready-to-use generic ObjectContext management framework. As you may see in the screenshot of the VS solution explorer below, I&amp;#39;ve created a 3-layered ASP.NET application.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=203" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author><category term="Entity Framework" scheme="http://community.icburner.com/blogs/webdev/archive/tags/Entity+Framework/default.aspx" /><category term="N-Tier" scheme="http://community.icburner.com/blogs/webdev/archive/tags/N-Tier/default.aspx" /></entry><entry><title>Oxite Review</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/oxite-review.aspx" /><id>/blogs/webdev/archive/2009/05/31/oxite-review.aspx</id><published>2009-05-31T04:11:34Z</published><updated>2009-05-31T04:11:34Z</updated><content type="html">&lt;p&gt;I’m really trying not to be negative with this post. The people behind Oxite are good folks and don’t deserve any hate.&amp;nbsp; They have made a mistake, though. A mistake I think needs to be corrected and requires some immediate action. &lt;p&gt;My advice, if anyone cares: &lt;ul&gt; &lt;li&gt;Oxite should be pulled immediately until the larger issues (including and especially the major security vulnerabilities) can be addressed satisfactorily.  &lt;li&gt;Oxite should NOT be used as any sort of Best Practice or official guidance by Microsoft. The Oxite folks have been VERY open and clear that this is NOT anything official or supposed to be recommended guidance. Unfortunately, though, many WILL take it as that no matter how many disclaimers they have to click though.  &lt;li&gt;If you are not familiar with ASP.NET MVC or MVC in general, you should avoid Oxite for the time being as there are several anti-patterns that may set you off on the wrong footing in the future. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;I would prefer not to go into any specific problems Oxite may have.&amp;nbsp; From my days as a consultant, I know that this will be taken as gospel by many and used off-the-shelf with little modification to build many production web applications.&amp;nbsp; This could be a minor disaster for many companies and other organizations who may be the unwitting victim of its problems.&amp;nbsp; This may seem overly dramatic, but if you have not spent any significant time consulting in the .NET space and aren’t aware of things like PetShop or the various ASP.NET quick start applications then trust me, it could become that bad – and fast. &lt;p&gt;The folks who are involved with Oxite’s development are open to communication and are engaging the community and are working with everyone to try to balance the needs of everyone.&amp;nbsp; However, until its most major issues (including significant security vulnerabilities) can be addressed, I think it would be best to pull it or lock it down on CodePlex to prevent it being referenced by the community and any more confusion spread. &lt;p&gt;We all have an opportunity to improve the .NET space here and I think we should take this opportunity.&amp;nbsp; ASP.NET MVC will soon be released, and I’d hate for the first major impression of its usage from Microsoft be problematic. &lt;p&gt;Finally, I appreciate the efforts of the Oxite-involed folks and the sincere attempt at openness and contribution. This is a significant contribution and we are very thankful for this. As much as many members may be upset about Oxite, underneath, I think everyone is appreciative (though we/they may have a bad way of showing it) that this even happened in the first place. This is definitely a step in the right direction.&amp;nbsp; The next step, I think, is to crank up the quality a little more so we can all have our cake and eat it, too! &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Several folks, including Microsoft employees and members of the Oxite team, have politely requested I do a post or few on the problems I see with Oxite and why I &lt;a href="http://www.lostechies.com/blogs/chad_myers/archive/2008/12/15/my-quick-take-on-oxite.aspx"&gt;previously recommended&lt;/a&gt; that it is not a good example/sample from which to base future products. &lt;p&gt;At first, I was reluctant to do this since I was afraid people might see it as some sort of attack or other negative. But since I have been encouraged by several folks as mentioned, I feel that this will be constructive and received as a “good thing”. &lt;h4&gt;Setup&lt;/h4&gt; &lt;p&gt;First, I want to make sure that everyone knows there’s no attack here, nothing personal, this is purely about code and in no way a reflection on the individual.&amp;nbsp; The way we roll at Dovetail is that we are dispassionate about our code and follow practices such as &lt;a href="http://www.extremeprogramming.org/rules/collective.html"&gt;collective code ownership&lt;/a&gt;, &lt;a href="http://www.extremeprogramming.org/rules/refactor.html"&gt;refactoring mercilessly&lt;/a&gt;, &lt;a href="http://www.extremeprogramming.org/rules/pair.html"&gt;pair programming&lt;/a&gt;, and &lt;a href="http://www.extremeprogramming.org/rules/optimize.html"&gt;no premature optimization&lt;/a&gt;, which help disassociate our passion, creativity, and soul from the code so that we can objectively look at parts and say “that is bad” or “this is good” and mean it.&amp;nbsp; So I’m coming from a viewpoint that the code is code and should be mercilessly, objectively torn apart and made to stand on its own merits, independent of who wrote it and under what conditions.&amp;nbsp; I say that code can be objectively determined to be “good” or “bad” and patterns and anti-patterns identified with certainty and no subjectivity. &lt;p&gt;Second, please consider Nate Kohari’s &lt;a href="http://kohari.org/2008/12/18/altnet-is-the-opposition-party/"&gt;recent great post&lt;/a&gt; on debate vs. argument; ego, pride, personal attachment, etc. as this also helps to frame where I’m coming from.&amp;nbsp; During this review, I’m not going to mention people, their motivations, their goals and desires, etc.&amp;nbsp; I’m only going to talk about the code and the requirements of the features the code is trying to accomplish. &lt;p&gt;With these things in mind, let us now objectively view Oxite as a body of work, independent of any individuals involved in its creation, that must stand alone and be evaluated solely on its own merits. &lt;h4&gt;As a Sample Application…&lt;/h4&gt; &lt;p&gt;Oxite is a “real world sample” and not necessarily official guidance (a la the Patterns &amp;amp; Practices type stuff).&amp;nbsp; As a sample, the packaging of Oxite is good as it includes many facets of a project from the domain, to the database, to the front end, etc.&amp;nbsp; Perhaps it could’ve included some more documentation (maybe I missed it? I didn’t look very hard, admittedly).&amp;nbsp; Since this wasn’t positioned as a guidance project, people should avoid referring other people to it as any sort of best practice or official anything from Microsoft.&amp;nbsp; As ASP.NET MVC matures after release, I expect we’ll start seeing more official guidance from P&amp;amp;P and other groups within Microsoft. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: [For MS, primarily, as this problem is mostly unique due to MS’ position with respect to .NET] Perhaps MS could establish more official terms to set expectations for customers. “Sample” is not “Guidance” is not “Recommendation” is not “Stance”, etc. &lt;h4&gt;As an OSS project…&lt;/h4&gt; &lt;p&gt;Oxite is an open-source project. It is released under the &lt;a href="http://www.opensource.org/licenses/ms-pl.html"&gt;Microsoft Public (Ms-PL) license&lt;/a&gt; which is quite permissive and in line with generally accepted good practices for open source. This is very good.&amp;nbsp; Oxite is hosted on the CodePlex project site and (correct me if I’m wrong) is not accepting patches from the public due to, I believe, concerns of patent/IP violations and such.&amp;nbsp; This is not very good. Part of being open is allowing people to modify it without having to fork the code.&amp;nbsp; At the very least, we can fork it which is certainly heads above what we normally get from large corporations which is either no visibility, or only push releases.&amp;nbsp; Overall, I’m very pleased MS has taken this approach with Oxite and I’d like to greatly encourage them to pursue this method of release in the future.&amp;nbsp; My only critique is that maybe they find a way to accept patches from the public (I’m ok if they need to fill out some affidavit or other legal form).&amp;nbsp;  &lt;p&gt;As a .NET OSS project, I was particularly disappointed in the fact that the high-level Visual Studio Team *.* SKU’s were used in its creation. I don’t have the numbers, but I’m willing to bet that the vast majority of .NET developers do not have the full Visual Studio suite (Database, Test, etc) and so they won’t even be able to open the SLN file without having to hack CSPROJ files and such (like I had to).&amp;nbsp; There is a SLN file for Visual Web Developer Express that will help get people going, but this seems like an afterthought, rather than a good strategy.  &lt;p&gt;Also missing is any sort of automated build script. What if I want to set up Oxite in my own CI server to pull down the trunk nightly and do builds in my environment?&amp;nbsp; This is pretty standard among .NET OSS projects, so I was disappointed that this was missing. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: [For MS and other companies seeking to release .NET OSS] Either let these things go out to be full OSS projects and release the copyright and liability to the public somehow to achieve full indemnity from possible patent or copyright infringement.&amp;nbsp; And/or, find a legal framework for being able to accept patches from individuals in the community. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: [For anyone managing an OSS project] Please take a little more care to ensure that you have respected generally accepted minimum expectations of an OSS project such as an automated build and decent test coverage. &lt;h4&gt;Tests!?!&lt;/h4&gt; &lt;p&gt;Technically, this should just go under the previous section, but it’s significant enough that it should be called out on its own. Unless I’m missing something, there are around 51 tests for the entire project and those tests cover only the MetaWeblog API handling and the XmlRpc handling.&amp;nbsp; Without having run a coverage tool, I’m guessing that coverage is below 10%. I’m very serious when I say that this would be considered unacceptable on most projects I’m involved with. I would be put on probation or possibly removed from a project at a corporate customer or removed as a committer on an OSS project for committing code with &amp;lt;10% coverage.&amp;nbsp; Quite frankly, it is dangerous to have a large application with &amp;lt;10% test coverage.&amp;nbsp; It is also a liability in that future changes become ever increasingly difficult with the friction and fear of change due to the unknown of how changes may break functionality and cause regression bugs. &lt;p&gt;The tests that are there (for example, I count 49 in the MetaWeblogServiceTests) are a little heavy. In my opinion, this indicates that &lt;a href="http://www.codeplex.com/oxite/SourceControl/changeset/view/27048#372212"&gt;MetWeblogService&lt;/a&gt; has too many responsibilities and is putting too much burden on the tests to account for the excessive dependencies of &lt;a href="http://www.codeplex.com/oxite/SourceControl/changeset/view/27048#372212"&gt;MetaWeblogService&lt;/a&gt;.&amp;nbsp; It’s also curious that no mocking framework was used, but instead (excessive, IMHO) use of fake, concrete test implementations were used.&amp;nbsp; Several(though not most) of the tests are asserting too many things which leads to brittle tests and can cause friction during refactoring.&amp;nbsp;  &lt;p&gt;Testing is not just about ensuring the current code works properly (that is important), but also explaining how the code works so that, in the future, when changes are made, maintenance programmers understand why the change they made broke other things.&amp;nbsp; This enhances change confidence and encourages fearless refactoring which is key to maintaining a rapid, sustainable pace throughout the life of the development. &lt;p&gt;But I digress, this subject is perhaps too large and requires a post in an of itself. Suffices to say that&amp;nbsp; there are too few tests and the tests that are there, while meaningful, will contribute to increased friction over the life of the product and should probably be refactored as the project goes on. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: [For anyone managing an OSS project] Tests serve many purposes including encouraging contributors because they can see how things are supposed to work, and can be more confident in their changes, knowing that tests will most likely catch them if they make a big mistake.&amp;nbsp; At this point, going BACK and adding tests would likely be a waste of time. Going forward, all new features should be developed with tests (preferably test-driven as this helps keep your design on track, it’s a curious side effect of writing client code FIRST, then the code to make it work).&amp;nbsp; Any bugs that pop up between now and then should first have a test that reproduces the problem, then the fix should be implemented, and the tests should then pass (without modification). If they don’t pass, the fix isn’t quite right.&amp;nbsp; If, during the fixing of bugs, you discover other problems or realize there’s more refactoring to do, do that code test-driven along with the bugfix. Try to keep changes minimal and focused, though, and with a high degree of coverage (preferably &amp;gt;90%, but that’s not a hard rule). &lt;p&gt;Test should be small, easy to write, and not require a lot of setup. If they’re not meeting ALL of these three criteria, you have a design problem and need to reinvestigate. It happens all the time that I find myself violating one or more of these rules, and the tests help to point me to where in my design I screwed up. This is a natural thing and shouldn’t be seen as negative. You caught the problem early and tests helped spot it and point you in the right direction. Just keep these criteria in mind as you proceed. &lt;h4&gt;Domain&lt;/h4&gt; &lt;p&gt;The heart of any good project is its domain. The domain is the understanding and model of the core problem this application is trying to solve.&amp;nbsp; The domain is king. It should be fat, juicy, and contain the core logic that constitutes how this application behaves. Everything else in the application serves the domain by either bringing information to it, or relaying information out of it to the customer (users, other applications, data storage, etc).&amp;nbsp; Great care and investment should be placed on the domain of the application as it is your greatest and most important asset.&amp;nbsp; Principles, patterns, and practices have evolved around this very integral part of application design. Entire books have been written. These include &lt;a href="http://domaindrivendesign.org/"&gt;&lt;em&gt;Domain Driven Design&lt;/em&gt;&lt;/a&gt; (Evans) and &lt;a href="http://www.amazon.com/Applying-Domain-Driven-Design-Patterns-Examples/dp/0321268202"&gt;&lt;em&gt;Applying Domain-Driven Design and Patterns: Using .NET&lt;/em&gt;&lt;/a&gt; (Nilsson), among many others. &lt;p&gt;An important part of key domain object model design is to do it independent of persistence concerns (known as “Persistence Ignorance”). Object Oriented Design is a fundamentally different problem than Relational Data Model Design and each should be done independent of the other to avoid the patterns of one being misapplied in the other.&amp;nbsp; The intermediary between the contrary physics of these two worlds is the Object/Relational Mapper (ORM) such as NHibernate, LLBLGen Pro, and, to a lesser extent, ADO.NET Entity Framework and the &lt;a href="http://ayende.com/Blog/archive/2008/10/31/microsoft-kills-linq-to-sql.aspx"&gt;now defunct&lt;/a&gt; Linq2SQL. &lt;p&gt;In Oxite, the domain appears to have been driven from the relational model (i.e. database) which has caused some interesting problems that had to be worked around and have hampered the domain (we’ll get to this later).&amp;nbsp; The data provider used was Linq2SQL.&amp;nbsp; Object/database design were achieved using the Linq2SQL designer-generated classes. These classes are partial classes which allow the application to create the other half of the partial class in another file. In these partial classes are added the property-changed, relationship, and other data-concerned handling/functionality. Also, each partial adds an interface (i.e. IPost for the oxite_Post object) presumably to hide away some of the details of Linq2SQL. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: Domain objects should be POCO objects with no attachments to or knowledge of the database whatsoever. You can have class hierarchies (but proceed cautiously and light here) and entities can have interfaces, but this should be a rare occurrence and should not required of all of them.&amp;nbsp; The objects should be able to be used and their functionality fully useful without requiring any backend infrastructure, services, database, etc. When it comes to persistence, the persistence framework should “just work” and support the objects naturally without them having to implement any special interfaces or have to do anything special (i.e. including support for transparent lazy loaded collections, and none of this EntitySet business).&amp;nbsp; If your ORM can’t do that, consider one of the already available, major, post 1.x version offerings that have been proving themselves for years on the market in battle. &lt;h5&gt;Linq2SQL Problems&lt;/h5&gt; &lt;p&gt;You may have noticed earlier when I said “to a lesser extent” when talking about Linq2SQL as an ORM. This is because Linq2SQL is missing a lot of key functionality to be considered as a full-fledged ORM.&amp;nbsp; Among these are automatic change-tracking and cascade support, transparent lazy loading, and database data-type minutiae handling.&amp;nbsp; These things are just a given in a more mature and full-featured ORM like NHibernate, for example. &lt;p&gt;I also said that the use of Linq2SQL has caused some interesting problems. Aside from having to manually do change tracking, deal with underlying SQL data-types, and having to deal with relationships manually, the Linq2SQL-based objects have the pernicious problem of not being able to be used (easily) without being connected to the database.&amp;nbsp; This is the opposite of “Persistence Ignorance.”&amp;nbsp; To counter this problem, Oxite has entity interfaces (i.e. IPost).&amp;nbsp; Generally speaking, interfaces for entities is a smell. In this case, the smell is definitely pointing to a problem and using interfaces is merely a band-aid for that problem. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: Don’t use Linq2SQL as it’s simply too much friction and lacks critical features.&amp;nbsp; Use a full-featured ORM like NHibernate or several of the commercial ones available. &lt;h5&gt;Interface Entities&lt;/h5&gt; &lt;p&gt;I mentioned above some of the problems with interface-based entities like IPost, ITag, etc. I wanted to call out a specific example of where something like this can go very wrong.&amp;nbsp; In the partial class declaration of class &lt;em&gt;oxite_Tag&lt;/em&gt;, the &lt;em&gt;Parent&lt;/em&gt; property has a significant problem for reuse and future maintenance. For reference, see &lt;a href="http://www.codeplex.com/oxite/SourceControl/changeset/view/27048#371337"&gt;PartialClasses.cs&lt;/a&gt;, line 646. &lt;p&gt;The problem with this property is that it means oxite_Tag is only valid with other oxite_Tag implementations of ITag. This is what’s known as a violation of the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov&lt;/a&gt; &lt;a href="http://www.lostechies.com/blogs/chad_myers/archive/2008/03/09/ptom-the-liskov-substitution-principle.aspx"&gt;Substituion&lt;/a&gt; &lt;a href="http://www.objectmentor.com/resources/articles/lsp.pdf"&gt;Principle&lt;/a&gt; and/or the &lt;a href="http://en.wikipedia.org/wiki/Open/closed_principle"&gt;Open&lt;/a&gt; &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc546578.aspx"&gt;Closed&lt;/a&gt; &lt;a href="http://www.objectmentor.com/resources/articles/ocp.pdf"&gt;Principle&lt;/a&gt;. Put simply, anyone doing anything with ITag would be surprised if they started getting InvalidCastExceptions because of some problem lurking deep in your design.&amp;nbsp; If the intention is that oxite_Tag can only work with other oxite_Tag’s, then it shouldn’t use an ITag interface when it doesn’t really mean it. &lt;p&gt;Is this nitpicking? Kinda. The oxite_Tag problem may never get hit, but it is a potential landmine in your code, waiting to explode on an unsuspecting maintenance programmer. If your design has special magic and gotchas, you have a problem.  &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: Interfaces should be intention revealing and their implementation contain no surprises.&amp;nbsp; Interfaces also should only be used where true abstraction is needed. Entities/domain modeling is generally one of these places where abstraction is not necessary (and therefore interfaces shouldn’t be used). &lt;h5&gt;Database Assumptions&lt;/h5&gt; &lt;p&gt;The entities in Oxite have several assumptions specifically about SQL Server (heavy use of SqlDateTime.Min/MaxValue).&amp;nbsp; This is yet another problem that stems from the of usage of Linq2SQL.&amp;nbsp; To address this, Oxite has abstracted entities (behind interfaces such as IPost, ITag, etc) and abstracted the repositories behind interfaces (good, actually!) and these repositories are accessed through an “IOxiteDataProvider” implementation, such as &lt;a href="http://www.codeplex.com/oxite/SourceControl/changeset/view/27048#371330"&gt;OxiteLinqToSqlDataProvider&lt;/a&gt; (bad, more on this later).&amp;nbsp; This is not the appropriate place to abstract database concerns.&amp;nbsp; I’ll cover proper layering and proper concern separation later. For now, the relevant point is that concerns about the specific usage of the underlying database have seeped up too high in the layering of the application, necessarily requiring more and more complex architecture and abstractions to work around this. This means implementing an “IOxiteDataProvider” is more difficult for would-be implementers than it should be and much duplication of code will likely result.&amp;nbsp; It also prohibits the use of a fat/rich domain model which leads me to the next section (Anemic Domain). &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: Keep database-specifics as close to the database as possible and, to the maximum extent possible, completely out of your application code. This is best handled by a persistence framework such as an ORM like NHibernate.&amp;nbsp; Doing this will make it much easier to implement different data access strategies later in the product’s life and to support a wider range of database platforms with little to no change to most of the application code. You’ll still have to test on each database you plan on supporting, but the code should not have to change (much) when adding support for a new database. &lt;h5&gt;Anemic Domain&lt;/h5&gt; &lt;p&gt;Another problem with the domain of Oxite is that all the entity objects are anemic with a few minor exceptions.&amp;nbsp; An &lt;a href="http://martinfowler.com/bliki/AnemicDomainModel.html"&gt;anemic domain model&lt;/a&gt; is one that is largely if not entirely comprised of getters/setters and are just data containers (DTOs for the database, if you will).&amp;nbsp; This necessarily forces all the interesting logic of the domain to be the responsibility of other, perhaps less appropriate, parties which can lead to “service explosion” or “manager anti-pattern”, etc. &lt;p&gt;Like I said earlier, domains should necessarily be fat and contain all the relevant logic. They should contain concepts such as “required” and “unique”, etc and these concepts should flow out into the rest of the application including into the relational database model.&amp;nbsp; The domain should prevent invalid states/situations and should enforce rules throughout the system.&amp;nbsp; This is not to be confused necessarily with the antiquated concept of a Business Logic Layer, however. &lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: The domain model should be “fat” and rich.&amp;nbsp; It should be modeled according to the current understanding of how the domain SHOULD work (i.e. X is required, there can only be 1 Y per every X, When an A is added to a B, that B’s “A” property should be set to the newly-related A instance, etc, etc, etc). &lt;h4&gt;Conclusion of Part 1&lt;/h4&gt; &lt;p&gt;It looks like this will be a multi-parter, because it’s already long and I haven’t even gotten to the majority of issues.&amp;nbsp; By the time this review is done, I’d like to cover the following things by the time I’m done (wish me luck): &lt;ul&gt; &lt;li&gt;Problems with the Provider anti-pattern  &lt;li&gt;Incorrect layering and slicing of abstractions  &lt;li&gt;Lack of Dependency Injection (in some cases) and IoC causes cascading design problems  &lt;li&gt;High Coupling, Low Cohesion  &lt;li&gt;Single Responsibility Principle, Separation of Concerns, and Interface Segregation Principle violations causing problems  &lt;li&gt;What is a “Controller” for?  &lt;li&gt;What is a “View” for?  &lt;li&gt;Mystery Meat, Magic Strings, and Bags of Holding +1  &lt;li&gt;Presentation Models  &lt;li&gt;Logic in Views Is Bad  &lt;li&gt;ASP.NET MVC guts leaking up into all parts of the app  &lt;li&gt;(other stuff that will probably come up in the comments that I didn’t think of) &lt;/li&gt;&lt;/ul&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=199" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author></entry><entry><title>实体框架中的POCO体验</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/poco.aspx" /><id>/blogs/webdev/archive/2009/05/31/poco.aspx</id><published>2009-05-31T03:53:01Z</published><updated>2009-05-31T03:53:01Z</updated><content type="html">&lt;p&gt;【译者按】 Entity Framework 1.0 发布也有一段时间了，但感觉用的人很少。其中一个很大的原因，也许就是不支持POCO。要知道，Entity Framework 1.0的做法是让你的实体从EF的基类继承而来，这对很多人，特别是崇尚DDD的人来说，那是一副难以下咽的药啊。曾有微软开发人员提供了一个 &lt;a href="http://code.msdn.microsoft.com/EFPocoAdapter"&gt;POCO Adapter&lt;/a&gt;，但那究竟不是正规的做法。Visual Studio 2010 和 .NET 4.0 提供了许许多多的新特性，真是让人激动，向往，大有一种回到.NET 1.0 刚出来时的感觉。春天啊（应该是夏天啊），你终于回来了（虽然早晨/晚上还是unseasonably冷）。其中的Entity Framework 4.0版本将提供POCO支持，对很多人来说，这是开始使用Entity Framework的时候了。&lt;a href="http://blogs.msdn.com/adonet/"&gt;ADO.NET 团队博客&lt;/a&gt;上贴出了一些关于EF和POCO的贴子，非常值得一读。 &lt;p&gt;【原文地址】&lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/21/poco-in-the-entity-framework-part-1-the-experience.aspx"&gt;POCO in the Entity Framework: Part 1 - The Experience&lt;/a&gt;&lt;br /&gt;【原文发表日期】 21 May 09 05:46 PM  &lt;p&gt;上个星期，我在《&lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/11/sneak-preview-persistence-ignorance-and-poco-in-entity-framework-4-0.aspx"&gt;POCO初览&lt;/a&gt;》中提到了POCO实体支持是我们加到Entity Framework 4.0中的新功能之一。这个星期，我要对Entity Framework 4.0中POCO支持的细节进行深入讨论。 &lt;p&gt;要讨论的东西很多，包括 &lt;ul&gt; &lt;li&gt;Entity Framework 4.0中总的POCO体验  &lt;li&gt;POCO的变化跟踪  &lt;li&gt;关系修整  &lt;li&gt;复杂类型  &lt;li&gt;延迟（懒式）装载和显式装载  &lt;li&gt;最佳实践 &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;在这个贴子中，我将主要着重于总的体验，这样，你可以马上启用Entity Framework 4.0中的POCO支持。我将使用一个简单的例子做示范，这样，你可以看到在Entity Framework 4.0中使用POCO的感觉。我将使用Northwind数据库，在随后的贴子中，将继续建立在这个例子的基础之上。 &lt;p&gt;&lt;b&gt;第一步：&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;创建模型，关闭默认的代码生成&lt;/b&gt; &lt;p&gt;虽然POCO允许你以透明持久化的方式编写自己的实体类，但还是有必要“接入”持久性和EF元数据，这样你的POCO实体可以从数据库中复原，以及持久化到数据库中。为实现这个，你还是需要使用实体框架设计器创建一个实体数据模型（Entity Data Model），或者提供跟你在Entity Framework 3.5中生成的完全一样的CSDL, SSDL 和 MSL 元数据文件。所以，首先，我将使用ADO.NET实体数据模型向导（Entity Data Model Wizard）来生成一个EDMX。 &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/adonet/WindowsLiveWriter/POCOintheEntityFrameworkPart1TheExperien_F9E4/image_2.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image002_5F00_1.gif" width="491" height="341" /&gt;&lt;/a&gt; &lt;ol&gt; &lt;li&gt;创建一个类库项目来定义你的POCO类型，我将其命名为&lt;b&gt;NorthwindModel&lt;/b&gt;。这个项目与持久性毫不相关，对实体框架没有依赖性。  &lt;li&gt;创建一个类库项目，它将包含与持久性相关的代码，我将其命名为&lt;b&gt;NorthwindData&lt;/b&gt;。这个项目除了对&lt;b&gt;NorthwindModel&lt;/b&gt;项目有依赖外，还对实体框架(System.Data.Entity)有依赖。  &lt;li&gt;在&lt;b&gt;NorthwindData&lt;/b&gt; 项目中&lt;b&gt;添加新项&lt;/b&gt;，加一个名为“&lt;b&gt;Northwind.edmx &lt;/b&gt;”的ADO.NET实体数据模型（这么做将自动在项目中添加对实体框架的依赖）。  &lt;li&gt;选择“从数据库生成”，给Northwind数据库建造模型  &lt;li&gt;暂时只选&lt;b&gt;Categories&lt;/b&gt;和&lt;b&gt;Products&lt;/b&gt;这两个你感兴趣的表到你的实体数据模型中。 &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;至此，生成了可以为我所用的实体数据模型，但在开始编写代码前，还有最后一步：关闭代码生成。毕竟你感兴趣的是POCO啊，请去除负责从&lt;b&gt;Northwind.edmx&lt;/b&gt;生成基于&lt;b&gt;EntityObject&lt;/b&gt;代码的&lt;b&gt;Custom Tool&lt;/b&gt;&lt;b&gt;（自定义工具）&lt;/b&gt;属性，这将关闭你的模型的相应代码生成。 &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/adonet/WindowsLiveWriter/POCOintheEntityFrameworkPart1TheExperien_F9E4/image_4.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image004_5F00_1.gif" width="501" height="348" /&gt;&lt;/a&gt; &lt;p&gt;现在，我们可以编写POCO实体了。 &lt;p&gt;&lt;b&gt;第二步：&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;编写你的&lt;/b&gt;&lt;b&gt;POCO&lt;/b&gt;&lt;b&gt;实体&lt;/b&gt; &lt;p&gt;我将为Category和Product编写简单的POCO实体，这些类将加到&lt;b&gt;NorthwindModel&lt;/b&gt;项目中去。注意，我在这里展示的，不应该看成是最佳实践，这里的意图只是示范可以工作的最简单的例子。在以后我们将根据需要将对这些例子进行扩展和定制，之后建立在其基础之上，使用&lt;b&gt;Repository&lt;/b&gt;和&lt;b&gt;Unit of Work&lt;/b&gt;模式做进一步的扩展。 &lt;p&gt;这里是Category实体的样例代码：&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class Category&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public int CategoryID { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string CategoryName { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Description { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public byte[] Picture { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public List&amp;lt;Product&amp;gt; Products { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;
&lt;p&gt;注意，在模型中我既为标量字段定义了属性，也定义了导航属性。模型中的导航属性（Navigation Property）转换成了List&amp;lt;Product&amp;gt;。
&lt;p&gt;类似地，Product实体可以这样编写：&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class Product&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public int ProductID { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string ProductName { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public int SupplierID { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string QuantityPerUnit { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public decimal UnitPrice { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int16 UnitsInStock { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int16 UnitsOnOrder { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int16 ReorderLevel { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Discontinued { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;public Category Category { get; set; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;
&lt;p&gt;在这个例子中，因为其间的关系，一个&lt;b&gt;Product&lt;/b&gt;只允许属于一个&lt;b&gt;Category&lt;/b&gt;，因此我们有一个对&lt;b&gt;Category&lt;/b&gt;的引用（而不象&lt;b&gt;Category&lt;/b&gt;中的导航属性，是一个&lt;b&gt;List&amp;lt;T&amp;gt;&lt;/b&gt;集合）。
&lt;p&gt;&lt;b&gt;第三步：&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;编写你的实体框架上下文&lt;/b&gt;
&lt;p&gt;为把所有这些东西结合在一起，我所要做的最后一件事情是，提供一个上下文实现（就象使用默认的代码生成时你得到的&lt;b&gt;ObjectContext&lt;/b&gt;实现一样）。上下文（context）是把持久化意识带进你的应用的胶水（glue），它允许你编写查询，将实体复原，以及将变化存回到数据库中去。该上下文将是&lt;b&gt;NorthwindData&lt;/b&gt;项目的一部分。
&lt;p&gt;为简单起见，我将我们的上下文类包括在了包含实体类型的同个类库项目中了，但在我们讨论诸如&lt;b&gt;Repository &lt;/b&gt;和&lt;b&gt;Unit of Work&lt;/b&gt;等模式时，我们将做这样的设置，即，你将拥有一个纯粹的POCO类库，不带任何一丝与持久性相关的东西。
&lt;p&gt;这里是针对我们场景的简单的上下文实现：&lt;pre&gt;public class NorthwindContext : ObjectContext&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp;&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public NorthwindContext() : base(&amp;quot;name=NorthwindEntities&amp;quot;, &lt;br /&gt;
&amp;quot;NorthwindEntities&amp;quot;)&amp;nbsp; &lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _categories = CreateObjectSet&amp;lt;Category&amp;gt;();&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _products = CreateObjectSet&amp;lt;Product&amp;gt;();&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt; &lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public ObjectSet&amp;lt;Category&amp;gt; Categories&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get &lt;/pre&gt;&lt;pre&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;/pre&gt;&lt;pre&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;return _categories; &lt;/pre&gt;&lt;pre&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;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private ObjectSet&amp;lt;Category&amp;gt; _categories;&lt;/pre&gt;&lt;pre&gt; &lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public ObjectSet&amp;lt;Product&amp;gt; Products&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&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;return _products;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; private ObjectSet&amp;lt;Product&amp;gt; _products;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;
&lt;p&gt;注意，&lt;b&gt;ObjectSet&lt;/b&gt;&amp;lt;&lt;b&gt;T&lt;/b&gt;&amp;gt; 是Entity Framework 4.0中引进的一个特殊的&lt;b&gt;ObjectQuery&lt;/b&gt;&amp;lt;&lt;b&gt;T&lt;/b&gt;&amp;gt;。
&lt;p&gt;就这么简单！现在你有了纯粹的POCO实体，一个简单的上下文，允许你编写象这样的查询：&lt;pre&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;NorthwindContext db = new NorthwindContext();&lt;/pre&gt;&lt;pre&gt; &lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var beverages = from p in db.Products&lt;/pre&gt;&lt;pre&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; where p.Category.CategoryName == &amp;quot;Beverages&amp;quot;&lt;/pre&gt;&lt;pre&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; select p;&lt;/pre&gt;
&lt;p&gt;从数据库中复原的实体是纯粹的POCO实体，你可以对这些实体做变动，将变动保存到数据库中，跟平常的&lt;b&gt;EntityObject&lt;/b&gt;或&lt;b&gt;IPOCO&lt;/b&gt;实体非常类似。你将得到实体框架提供的所有服务，唯一的区别是，你现在使用的是纯粹的POCO实体。
&lt;p&gt;就我们的简化了的例子而言，尚有无数改进的可能性。但在那之前，我想先把一些基本的问题解决掉。
&lt;p&gt;&lt;b&gt;在使用&lt;/b&gt;&lt;b&gt;POCO&lt;/b&gt;&lt;b&gt;之前我需要一个实体数据模型么？&lt;/b&gt;
&lt;p&gt;是的，Entity Framework 4.0中的POCO支持只是去除了在你的实体类中带特定于持久性的关注的需求而已。但还是需要你提供CSDL/SSDL/MSL (总称EDMX)元数据，这样实体框架才能够将你的实体和元数据结合起来，以允许你访问数据。我们还在另外开发一个东西，它允许你做真正的“代码优先（code-first）”的开发，而不需要预先定义好的EDMX模型。这个功能的社区预览版将在几个月内在网上发布，一有机会我们就会将其加入实体框架。一如既往，你的反馈对我们极其有用。
&lt;p&gt;&lt;b&gt;我始终都只能手写这些实体和上下文么？&lt;/b&gt;
&lt;p&gt;不， Entity Framework 4.0中有一个非常强大和灵活的代码生成机制，该机制是基于T4之上的（Alex曾&lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/19/sneak-peek-using-code-generation-templates-with-the-entity-framework-4-0.aspx"&gt;在这里&lt;/a&gt;的博客上讨论过）。你可以提供你自己的模板，允许你按照你自己选择的方式建造实体。我们还在努力，以提供一些标准的模板，可为你生成POCO实体。
&lt;p&gt;&lt;b&gt;使用&lt;/b&gt;&lt;b&gt;POCO&lt;/b&gt;&lt;b&gt;实体时，元数据是怎么映射的？&lt;/b&gt;
&lt;p&gt;在Entity Framework 3.5中，基于&lt;b&gt;EntityObject&lt;/b&gt;和&lt;b&gt;IPOCO&lt;/b&gt;的实体都是依赖着使用映射特性（attributes），对实体类型和属性进行修饰和映射到概念性模型中对应的元素的。Entity Framework 4.0 引入了基于约定（convention）的映射，以允许不用显式的修饰，就可将实体类型，属性，复杂类型和关系映射到概念性模型。一个简单的规则是，在你的POCO类中使用的实体类型名称，属性名称，和复杂类型名称必须匹配那些在概念性模型中定义了的相应名称。命名空间的名称不在考虑之中，类中的命名空间定义和概念性模型中的命名空间定义不必相符。
&lt;p&gt;&lt;b&gt;我的实体类中的所有属性都需要有公开的&lt;/b&gt;&lt;b&gt;getters&lt;/b&gt;&lt;b&gt;和&lt;/b&gt;&lt;b&gt;setters&lt;/b&gt;&lt;b&gt;么？&lt;/b&gt;&lt;b&gt; &lt;/b&gt;
&lt;p&gt;你可以在你的POCO类型的属性上使用任何访问控制修饰符（access modifier），只要被映射的任何属性都不是虚拟的，以及你不需要局部信任（partial trust）支持。在局部信任下运行时，对你的实体类的访问控制修饰符的可见性有一些特定的要求。我们将对在涉及局部信任时，所支持的完整的访问控制修饰符集提供详细的文档。
&lt;p&gt;&lt;b&gt;对基于集合的导航属性都支持哪些集合类型？&lt;/b&gt;
&lt;p&gt;任何属于&lt;b&gt;ICollection&amp;lt;T&amp;gt;&lt;/b&gt;的类型都是支持的。如果你对&lt;b&gt;ICollection&amp;lt;T&amp;gt;&lt;/b&gt;类型的字段不以具体的类型初始化的话，那么从数据库中复原实体集合时， 将提供&lt;b&gt;List&amp;lt;T&amp;gt;&lt;/b&gt;。
&lt;p&gt;&lt;b&gt;我可以有单向的关系么？例如，我想在我的&lt;/b&gt;&lt;b&gt;Product&lt;/b&gt;&lt;b&gt;类中有一个&lt;/b&gt;&lt;b&gt; Category &lt;/b&gt;&lt;b&gt;属性，但在&lt;/b&gt;&lt;b&gt;Category&lt;/b&gt;&lt;b&gt;类中我不想要一个&lt;/b&gt;&lt;b&gt;Products&lt;/b&gt;&lt;b&gt;集合。&lt;/b&gt;
&lt;p&gt;是的，这是支持的。唯一的限制是，你的实体类型必须反映模型中所定义的东西。如果你不想拥有对应于关系的某一边的导航属性的话，那么你需要从模型中将其完全剔除。
&lt;p&gt;&lt;b&gt;POCO&lt;/b&gt;&lt;b&gt;支持延迟（懒式）装载么？&lt;/b&gt;
&lt;p&gt;是的，POCO是通过使用代理类型来支持延迟（懒式）装载的，这些代理类型是在你的POCO类之上提供自动的懒式装载行为的。在讨论到延迟装载时，我们会对此做详述，在那之前，知道一下我们也支持通过使用“&lt;b&gt;Include&lt;/b&gt;”来实现的早期装载（eager loading），象这样：&lt;pre&gt;var beverageCategory = (from c in context.Categories&lt;br /&gt;
.Include(&amp;quot;Products&amp;quot;)&lt;/pre&gt;&lt;pre&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; where c.CategoryName == &amp;quot;Beverages&amp;quot;&lt;/pre&gt;&lt;pre&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; select c).Single();&lt;/pre&gt;
&lt;p&gt;如果我要使用延迟（懒式）装载的话，我不用这么做， 在讨论代理时我们会对此进行讨论。
&lt;h6&gt;修整（fix-up）关系&lt;/h6&gt;
&lt;p&gt;要了解有2种类型的修整：1)查询时的修整, 2) 对你的实体/关系进行改动时的修整。
&lt;p&gt;&lt;b&gt;&lt;u&gt;查询时的修整&lt;/u&gt;&lt;/b&gt;&lt;u&gt; &lt;/u&gt;
&lt;p&gt;查询时的修整是在同一个&lt;b&gt;ObjectContext&lt;/b&gt;上使用不同的查询来装载相关的实体时发生的。例如，如果我查询了一个分类实例“&lt;b&gt;Beverages&lt;/b&gt;&lt;b&gt;（饮料）&lt;/b&gt;”，之后又查询一个产品实例“&lt;b&gt;Chai&lt;/b&gt;”（是在&lt;b&gt;Beverages&lt;/b&gt;分类中的），我想要&lt;b&gt;chai.Category&lt;/b&gt; 指向&lt;b&gt;Beverages&lt;/b&gt;分类实例，不用我做额外的工作。
&lt;p&gt;这在今天是自动的，而且已经工作。
&lt;p&gt;&lt;b&gt;&lt;u&gt;对你的实体&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;/&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;关系进行改动时的修整&lt;/u&gt;&lt;/b&gt;
&lt;p&gt;这是在添加/去除与另一个实体相关的实体或者改变关系时两个实体间的关系修整。设想一下这样的例子：在我创建一个名叫&lt;b&gt;“Diet Chai”&lt;/b&gt;的新产品时，我想要将其与&lt;b&gt;Beverages &lt;/b&gt;分类相关联。
&lt;p&gt;在Entity Framework 4.0 Beta1 中，在这种情形下，POCO实体得不到自动的关系修整。在处理实体间的关系变动时，你需要确认你的POCO类型包含了在关系两头正确处理关系修整的逻辑。
&lt;p&gt;例如，在我的Northwind例子中，我在&lt;b&gt;Category&lt;/b&gt;上定义了如下的方法，以支持添加/去除订单。&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void AddProduct(Product p)&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Products == null)&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&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; Products = new List&amp;lt;Product&amp;gt;();&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt; &lt;/pre&gt;&lt;pre&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;if (!Products.Contains(p))&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&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; Products.Add(p);&lt;/pre&gt;&lt;pre&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;&lt;/pre&gt;&lt;pre&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;/pre&gt;&lt;pre&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;p.Category = this;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;
&lt;p&gt;总的来说，使用象这样的模式来支持添加/去除相关项，要比使用关系集合来添加/去除相关实体为好。你还可以选择将实际由EF支持的集合的getter/setter变成私有或内部访问控制，来支持更为细颗粒的访问，但就象前面提到的那样，其中一些东西取决于你是否需要局部信任支持这样的需求。
&lt;p&gt;我们在这个“简短的综述”中对总的POCO体验做了一番讨论。要讨论的东西还有很多很多，下个星期我将继续这个讨论。与此同时，请看一下附件中的完整解决方案，如果你对我们在这里讨论的所有概念的相应例程代码感兴趣的话。请记住，你必须在运行这个例程的机器上安装一个本地Northwind数据库。
&lt;p&gt;在下一个贴子中，我们将看一下复杂类型，变化跟踪，代理，懒式装载和早期装载。在那之前，请阅读一下MSDN&lt;a href="http://msdn.microsoft.com/en-us/library/dd456853(VS.100).aspx"&gt;这里&lt;/a&gt;的关于POCO的文档，以了解Entity Framework 4.0中的POCO支持的细节。
&lt;p&gt;请告知我们你们的想法！
&lt;p&gt;Faisal Mohamood &lt;br /&gt;Entity Framework的Program Manager
&lt;p&gt;附件： &lt;a href="http://blogs.msdn.com/adonet/attachment/9634552.ashx"&gt;NorthwindPocoSamplePart1.zip&lt;/a&gt;
&lt;h6&gt;&lt;/h6&gt;
&lt;h6&gt;复杂类型（Complex Types）&lt;/h6&gt;
&lt;p&gt;POCO中的复杂类型支持跟常规的基于&lt;b&gt;EntityObject&lt;/b&gt;的实体中的复杂类型支持一样。你要做的就是将它们声明为POCO类，然后在你的POCO实体中使用和声明基于它们的属性。
&lt;p&gt;作为例子，这里是一个&lt;b&gt;InventoryDetail&lt;/b&gt;复杂类型，代表我的Product实体的一个部分：&lt;pre&gt;public class InventoryDetail&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int16 UnitsInStock { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int16 UnitsOnOrder { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int16 ReorderLevel { get; set; }&lt;br /&gt;
} &lt;/pre&gt;
&lt;p&gt;把我的&lt;b&gt;Product&lt;/b&gt;类修改成包含一个这个类型的属性，用来组合几个有关库存细节的字段：&lt;pre&gt;public class Product&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public int ProductID { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string ProductName { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public int SupplierID { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string QuantityPerUnit { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public decimal UnitPrice { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public InventoryDetail InventoryDetail { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Discontinued { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public Category Category { get; set; }&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;然后你可以做你以前对复杂类型所能做的一切，这是一个查询的例子：&lt;pre&gt;var outOfStockProducts = from c in context.Products&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; where c.InventoryDetail.UnitsInStock == 0&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; select c;&lt;/pre&gt;
&lt;p&gt;你可以看到，POCO中的复杂类型支持用起来非常直截了当。但在POCO中使用复杂类型支持时，你需要记住几件事情：
&lt;ol&gt;
&lt;li&gt;你必须将复杂类型定义为类（class），结构体（struct）是不支持的。 
&lt;li&gt;在你的复杂类型类中，你不能使用继承。 &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;既然在讨论复杂类型，我想我要提一下另外一件事，你知道Visual Studio 2010中的实体框架设计器支持复杂类型的声明么？
&lt;p&gt;在Visual Studio 2008中，你只能手工将复杂类型的声明加到CSDL中去，但随着Visual Studio 2010中的设计器中对复杂类型支持的推出，这一切都成了历史。
&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/adonet/WindowsLiveWriter/POCOintheEntityFrameworkPart2ComplexType_148A3/image_2.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image006_5F00_1.gif" width="491" height="361" /&gt;&lt;/a&gt;
&lt;p&gt;更酷的是，因为Visual Studio 2010支持多定向（Multi-Targeting），你可以在开发针对.NET Framework 3.5，使用了Entity Framework 3.5的应用中也使用这个功能！
&lt;h6&gt;延迟/懒式装载&lt;/h6&gt;
&lt;p&gt;在我2个星期前发表的《&lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/12/sneak-preview-deferred-loading-in-entity-framework-4-0.aspx"&gt;延迟装载初览&lt;/a&gt;》一文中，我提到了实体框架现在支持延迟装载了。默认的、代码生成的基于&lt;b&gt;EntityObject&lt;/b&gt;的实体类型将提供延迟装载，自然毫不奇怪。如果你想知道POCO对象中是否也支持延迟装载，那么我想，你会很高兴地知道，你在POCO中也能得到延迟装载支持。
&lt;p&gt;为在POCO实体中使用延迟装载支持，你需要做2件事情：
&lt;ol&gt;
&lt;li&gt;将你想要懒式装载的属性声明为&lt;b&gt;virtual&lt;/b&gt;，这些属性可以是任何实现了&lt;b&gt;ICollection&amp;lt;T&amp;gt; &lt;/b&gt;的集合类，或者它们可以是代表了1/0..1 关系的引用。 &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;例如，这里是更新过的&lt;b&gt;Category&lt;/b&gt;实体类的部分代码，我将其改成支持延迟装载了：&lt;pre&gt;public class Category&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public int CategoryID { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string CategoryName { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Description { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public byte[] Picture { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual List&amp;lt;Product&amp;gt; Products { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ...&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.&amp;nbsp;&amp;nbsp; 在上下文中启用延迟装载选项：&lt;pre&gt;context.ContextOptions.DeferredLoadingEnabled = true;&lt;/pre&gt;
&lt;p&gt;这就行了，你现在就将得到POCO类型的自动延迟装载，而不用做任何其他什么事情。
&lt;p&gt;&lt;b&gt;那么这玩意到底是怎么工作的，底层是怎么进行的？&lt;/b&gt;
&lt;p&gt;这玩意能工作的原因是因为，在我将集合类型的属性标记为&lt;b&gt;virtual&lt;/b&gt;后，这允许实体框架在运行时为我的POCO类型提供一个&lt;b&gt;代理（&lt;/b&gt;&lt;b&gt;proxy&lt;/b&gt;&lt;b&gt;）&lt;/b&gt; 实例，正是这个代理实现了自动的延迟装载。该代理实例是基于一个继承自我的POCO实体类的类型，所以你提供的所有功能都被保留下来了。从开发人员的角度来看，即使延迟装载或许是个需求，这也允许你编写透明持久性的代码。
&lt;p&gt;如果你在调试器中检查实际的实例时，你会看到该实例的底层类型与我原先声明的类型是不同的：
&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/adonet/WindowsLiveWriter/POCOintheEntityFrameworkPart2ComplexType_148A3/image_4.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image008_5F00_1.gif" width="492" height="179" /&gt;&lt;/a&gt;
&lt;p&gt;虽然实体框架尽力以最小的摩擦提供自动的延迟装载，但在处理你想要添加或附加手工生成的实例时，或者当你序列化/发序列化实例时，这是你需要知道的事情。
&lt;p&gt;&lt;b&gt;&lt;u&gt;为&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;POCO&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;实体手工生成代理实例&lt;/u&gt;&lt;/b&gt;
&lt;p&gt;为了允许可以添加或附加的代理实例的生成，你可以使用ObjectContext上的CreateObject工厂方法来生成实体实例：&lt;pre&gt;Category category = context.CreateObject&amp;lt;Category&amp;gt;();&lt;/pre&gt;
&lt;p&gt;要把这个记住，在生成你想要用于实体框架的实例时，要使用&lt;b&gt;CreateObject&lt;/b&gt;。
&lt;h6&gt;用“变动跟踪代理（Change Tracking Proxies）”来提供更有效的变动跟踪&lt;/h6&gt;
&lt;p&gt;到目前为止，我们讨论过的标准POCO实体都依赖于基于快照（snapshot）的变动跟踪，即，实体框架会保管实体变动之前的值和关系的快照，这样，在保存（Save）时，可以与当前的值做比较。但这个比较的花销是相当大的，如果跟基于EntityObject的实体的变动跟踪的方式相比的话。
&lt;p&gt;还有另外一种类型的代理，它允许你在使用POCO实体时得到比较好的变动跟踪性能。
&lt;p&gt;如果你熟悉IPOCO接口，你知道&lt;b&gt;IEntityWithChangeTracker&lt;/b&gt;是要求你在类中实现、来向实体框架提供变动通知的接口之一。
&lt;p&gt;&lt;b&gt;变动跟踪代理&lt;/b&gt;从你的POCO实体类继承而来，在运行时给你提供这个功能，而不要求你自己实现IPOCO接口。
&lt;p&gt;从许多方面讲，用这种方式的话，你是鱼与熊掌都兼得了：你得到了POCO类的透明持久性，在变动跟踪方面你也得到了&lt;b&gt;EntityObject&lt;/b&gt; / &lt;b&gt;IPOCO&lt;/b&gt; 的性能。
&lt;p&gt;为了得到变动跟踪代理，基本的规则是，你的类必须是公开的，非抽象的或者非密封的（non-sealed）。你的类对所有要持久的属性都必须实现公开的virtual getters/setters。最后，你必须将基于集合的关系导航属性严格声明为ICollection&amp;lt;T&amp;gt;。它们不能是具体的实现或者继承自ICollection&amp;lt;T&amp;gt;的另外的接口（与延迟装载代理有所不同）。
&lt;p&gt;这里是我的&lt;b&gt;Product&lt;/b&gt; POCO类的例子，它将在运行时给我提供更有效的基于代理的变动跟踪：&lt;pre&gt;public class Product&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual int ProductID { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual string ProductName { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual int SupplierID { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual string QuantityPerUnit { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual decimal UnitPrice { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual InventoryDetail InventoryDetail { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual bool Discontinued { get; set; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public virtual Category Category { get; set; }&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;再说一遍，要记住，如果你要将实体加到或附加到上下文的话，你必须使用&lt;b&gt;CreateObject&lt;/b&gt;来生成代理实例。但不依赖代理的纯粹的POCO实体和基于代理的实体可以共处。你只有在涉及基于代理的实体时才需使用CreateObject。
&lt;p&gt;&lt;b&gt;如果我想在同个&lt;/b&gt;&lt;b&gt;POCO&lt;/b&gt;&lt;b&gt;类型中同时启用延迟装载和更好的变动跟踪，该怎么办？&lt;/b&gt;
&lt;p&gt;这两个东西不是互相排斥的，你不必在延迟装载代理和变动跟踪代理间做选择。如果你想要延迟装载，以及有效的变动跟踪，你只要按照变动跟踪代理的规则办，以及启用延迟装载选项。变动跟踪代理会给你提供延迟装载，如果延迟装载选项是启用了的话。
&lt;h6&gt;显式装载&lt;/h6&gt;
&lt;p&gt;这个延迟装载的功能确实很棒，但你们中很多人大概想要完全控制你是如何装载相关实体的吧。你甚至会选择走纯粹的POCO之路，而不诉诸于任何自动代理生成能给你提供的功能。
&lt;p&gt;这是完全可以接受的，（在很多情形下也许是更好的方法），你可以使用显式关系装载，对你是如何在数据库中查询数据的做完全的控制。
&lt;p&gt;在POCO中做&lt;b&gt;显式装载&lt;/b&gt;，有2个选项：
&lt;p&gt;一个是使用 &lt;b&gt;ObjectContext.LoadProperty &lt;/b&gt;，设置你想要装载的导航属性的名称：&lt;pre&gt;context.LoadProperty(beveragesCategory, &amp;quot;Products&amp;quot;);&lt;/pre&gt;
&lt;p&gt;这是可行的，但你可以看出来，这并不类型安全（type safe）。如果我没有正确的导航属性的名称的话，我会得到一个运行时异常。
&lt;p&gt;你们中的一些人大概更喜欢这个：&lt;pre&gt;context.LoadProperty(beveragesCategory, c =&amp;gt; c.Products);&lt;/pre&gt;
&lt;p&gt;我可以使用lambda表达式来指定我想要显式装载的属性，这提供了更好的类型安全。
&lt;p&gt;上面是我计划在这第二个贴子里讨论的所有的内容了。但以后还会有更多内容，在这个系列的最后一篇里，我们将讨论在处理纯POCO（非代理化的）实例以及在你的对象图和对象状态管理器（Object State Manager）间保持一致时需要知道的几件事情。我们也会讨论你也许想要知道的SaveChanges方法的多个变种。
&lt;p&gt;与此同时，请看一下我更新过的样例代码，其中包括了我们在本贴里讨论过的一些东西。
&lt;p&gt;Faisal Mohamood &lt;br /&gt;Entity Framework的Program Manager
&lt;p&gt;附件: &lt;a href="http://blogs.msdn.com/adonet/attachment/9647609.ashx"&gt;NorthwindPocoSamplePart2.zip&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=198" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author><category term="Entity Framework" scheme="http://community.icburner.com/blogs/webdev/archive/tags/Entity+Framework/default.aspx" /><category term="POCO" scheme="http://community.icburner.com/blogs/webdev/archive/tags/POCO/default.aspx" /></entry><entry><title>Implementing Audit Trail using Entity Framework</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/implementing-audit-trail-using-entity-framework.aspx" /><id>/blogs/webdev/archive/2009/05/31/implementing-audit-trail-using-entity-framework.aspx</id><published>2009-05-31T02:25:21Z</published><updated>2009-05-31T02:25:21Z</updated><content type="html">&lt;ul&gt; &lt;li&gt;&lt;a href="http://www.codeproject.com/ImplAudingTrailUsingEFP1/ImplAuditTrailUsingEFPart1.zip"&gt;Download source - 248.75 KB&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;Introduction&lt;/h4&gt; &lt;p&gt;Entity framework keeps track of those entire objects and relationships which have been deleted, added and modified in the container. EF keeps the state of the object and holds the necessary change-information and all the track information for each object or relationship resides as &lt;code&gt;objectStateEntry&lt;/code&gt;. Using &lt;code&gt;ObjectStateManager&lt;/code&gt;, one can access all this change-information like object-state (added/modified/deleted), modified properties, original and current values and can easily do audit trail for those objects. To get the Rollback feature from that audit trail, we have to consider some issues. We have to maintain the order of entity graph while doing&amp;nbsp;insertion and deletion. That means root entity has been inserted before the children and during deletion we have to make it reverse. The most important issue is that we have to make sure that audit trail entry will be inserted according to this order.  &lt;p&gt;So now I am going to talk about audit trail implementation that’s capable to rollback to a certain period. To make such an implementation, I am going to use the Entity framework’s caching Management that is called &lt;code&gt;ObjectStateManager&lt;/code&gt;. Using this manager, I will be capable&amp;nbsp;of finding out the object that is currently changed or added or deleted and resides in EF cache as Object state entry. In part 1, I am just going to talk about creating audit trail objects using the object state entry. In Part II, we&amp;nbsp;will talk about roll back feature of this audit trial. &lt;h4&gt;Using the Code &lt;/h4&gt; &lt;p&gt;First, I make the table audit trail in the database: &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_1.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_1.png" width="345" height="201" /&gt;&lt;/a&gt;  &lt;p&gt;For this table, I am going to make an Entity set in my conceptual level as: &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb.png" width="296" height="432" /&gt;&lt;/a&gt;  &lt;p&gt;In Entity Framework, to save all my changes into&amp;nbsp;database, we have to call &lt;code&gt;Context.SaveChanges()&lt;/code&gt; and this context is a container that has been inherited from &lt;code&gt;ObjectContext&lt;/code&gt; class.To create the Audit trail Objects for each “Modified/Added/Deleted”, I am going to catch the event:  &lt;p&gt;&amp;nbsp;&lt;pre&gt;Context.SavingChanges +=new EventHandler(Context_SavingChanges);&lt;/pre&gt;
&lt;p&gt;In the sample program, I have done it by writing partial class: 
&lt;p&gt;&amp;nbsp;&lt;pre&gt;public partial class AdventureWorksEntities
{ partial void OnContextCreated()
{
    this.SavingChanges += new EventHandler(AdventureWorksEntities_SavingChanges);
}

void AdventureWorksEntities_SavingChanges(object sender, EventArgs e)
{&lt;/pre&gt;
&lt;p&gt;So in my &lt;code&gt;AdventureWorksEntities_SavingChanges&lt;/code&gt; method, I am going to create all &lt;code&gt;dbaudit&lt;/code&gt; objects that are going to save in DB. Here it takes each entry from EF cache of state- Added or Deleted or Modified and calls a factory method to produce audit trail object. 
&lt;p&gt;&amp;nbsp;&lt;pre&gt;public partial class AdventureWorksEntities
{
    public string UserName { get; set; }
    List&amp;lt;DBAudit&amp;gt; auditTrailList = new List&amp;lt;DBAudit&amp;gt;();

    public enum AuditActions
    {
        I,
        U,
        D
    }

    partial void OnContextCreated()
    {
        this.SavingChanges += new EventHandler(AdventureWorksEntities_SavingChanges);
    }

    void AdventureWorksEntities_SavingChanges(object sender, EventArgs e)
    {
        IEnumerable&amp;lt;ObjectStateEntry&amp;gt; changes = 
            this.ObjectStateManager.GetObjectStateEntries(
            EntityState.Added | EntityState.Deleted | EntityState.Modified);
        foreach (ObjectStateEntry stateEntryEntity in changes)
        {
            if (!stateEntryEntity.IsRelationship &amp;amp;&amp;amp;
            stateEntryEntity.Entity != null &amp;amp;&amp;amp;
            !(stateEntryEntity.Entity is DBAudit))
            {//is a normal entry, not a relationship
                DBAudit audit = this.AuditTrailFactory(stateEntryEntity, UserName);
                auditTrailList.Add(audit);
            }
        }

        if (auditTrailList.Count &amp;gt; 0)
        {
            foreach (var audit in auditTrailList)
            {//add all audits 
                this.AddToDBAudit(audit);
            }
        }
    }&lt;/pre&gt;
&lt;p&gt;And here &lt;code&gt;AuditTrailFactory&lt;/code&gt; is a Factory method to create &lt;code&gt;dbaudit &lt;/code&gt;object.Specially for the Modify state, it keeps the modified properties and is serialized as XML. So using these fields,&amp;nbsp;you can easily show the changes of modified object by doing any comparison of old and new data. 
&lt;p&gt;&amp;nbsp;&lt;pre&gt;private DBAudit AuditTrailFactory(ObjectStateEntry entry, string UserName)
{
    DBAudit audit = new DBAudit();
    audit.AuditId = Guid.NewGuid().ToString();
    audit.RevisionStamp = DateTime.Now;
    audit.TableName = entry.EntitySet.Name;
    audit.UserName = UserName;

    if (entry.State == EntityState.Added)
    {//entry is Added 
        audit.NewData = GetEntryValueInString(entry, false);
        audit.Actions = AuditActions.I.ToString();
    }
    else if (entry.State == EntityState.Deleted)
    {//entry in deleted
        audit.OldData = GetEntryValueInString(entry, true);
        audit.Actions = AuditActions.D.ToString();
    }
    else
    {//entry is modified
        audit.OldData = GetEntryValueInString(entry, true);
        audit.NewData = GetEntryValueInString(entry, false);
        audit.Actions = AuditActions.U.ToString();

        IEnumerable&amp;lt;string&amp;gt; modifiedProperties = entry.GetModifiedProperties();
        //passing collection of mismatched Columns name as serialized string 
        audit.ChangedColumns = XMLSerializationHelper.XmlSerialize(
            modifiedProperties.ToArray());
    }

    return audit;
}&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;GetEntryValueInString&lt;/code&gt; is for creating XML text of previous or modified object. In Entity Framework, each entry holds all change definition. First I make a clone of the current object. Using &lt;code&gt;entry.GetModifiedProperties()&lt;/code&gt;, I can get only modified properties of an object and using &lt;code&gt;OriginalValues&lt;/code&gt; and &lt;code&gt;CurrentValues&lt;/code&gt;, I can build myself the old data and new data. Factory has told me what that wants – old or new. At the end, I have serialized XML and return back XML &lt;code&gt;string&lt;/code&gt;.
&lt;p&gt;&amp;nbsp;&lt;pre&gt;private string GetEntryValueInString(ObjectStateEntry entry, bool isOrginal)
{
    if (entry.Entity is EntityObject)
    {
        object target = CloneEntity((EntityObject)entry.Entity);
        foreach (string propName in entry.GetModifiedProperties())
        {
            object setterValue = null;
            if (isOrginal)
            {
                //Get original value 
                setterValue = entry.OriginalValues[propName];
            }
            else
            {
                //Get original value 
                setterValue = entry.CurrentValues[propName];
            }
            //Find property to update 
            PropertyInfo propInfo = target.GetType().GetProperty(propName);
            //update property with original value 
            if (setterValue == DBNull.Value)
            {//
                setterValue = null;
            }
            propInfo.SetValue(target, setterValue, null);
        }//end foreach

        XmlSerializer formatter = new XmlSerializer(target.GetType());
        XDocument document = new XDocument();

        using (XmlWriter xmlWriter = document.CreateWriter())
        {
            formatter.Serialize(xmlWriter, target);
        }
        return document.Root.ToString();
    }
    return null;
}&lt;/pre&gt;
&lt;p&gt;To clone the entity, I have used the method which I have found in an MSDN forum post (Thanks to Patrick Magee): 
&lt;p&gt;&amp;nbsp;&lt;pre&gt;public EntityObject CloneEntity(EntityObject obj)
{
    DataContractSerializer dcSer = new DataContractSerializer(obj.GetType());
    MemoryStream memoryStream = new MemoryStream();

    dcSer.WriteObject(memoryStream, obj);
    memoryStream.Position = 0;

    EntityObject newObject = (EntityObject)dcSer.ReadObject(memoryStream);
    return newObject;
}&lt;/pre&gt;
&lt;p&gt;That is all for Part 1 where I just create the Audit trail objects for each CUD operation.
&lt;p&gt;&amp;nbsp;
&lt;p&gt;· &lt;a href="http://www.codeproject.com/KB/database/ImplAudingTrailUsingEFP-2/ImplAuditTrailUsingEF.zip"&gt;Download source - 317.88 KB &lt;/a&gt;
&lt;p&gt;&lt;img border="0" alt="http://www.codeproject.com/KB/database/ImplAudingTrailUsingEFP-2/DataBaseDbAudit.JPG" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image001.jpg" width="341" height="197" /&gt;
&lt;p&gt;&lt;a href="http://www.codeproject.com/KB/database/ImplAudingTrailUsingEFP-2/DBAuditData.JPG"&gt;&lt;img border="0" alt="Click to enlarge image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image002.jpg" width="640" height="165" /&gt;&lt;/a&gt;
&lt;p&gt;&lt;b&gt;Introduction&amp;nbsp;&lt;/b&gt;
&lt;p&gt;I talked about creating audit trail objects using the object state entries. As I said earlier, in the second part I will talk about roll back feature of this audit trail. In the &lt;a href="http://www.codeproject.com/KB/database/www.codeproject.com/KB/database/ImplAudingTrailUsingEFP1.aspx"&gt;first part&lt;/a&gt;, I already described that to get the Rollback feature from that audit trail, we have to consider some issues. We have to maintain the order of entity graph while inserting and deleting. That means the root entity has been inserted before the children and during deletion, we have to&amp;nbsp;reverse it. The most important issue is that we have to make sure that each audit trail entry has been inserted according to this order. So during insertion of object, we also need to consider these things:&amp;nbsp;
&lt;ol&gt;
&lt;li&gt;Maintain insertion date-time to sort the audit trial 
&lt;li&gt;Store the old data and new data 
&lt;li&gt;Store the state of the data as audit action &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;If user chooses a certain time to roll back, we have to start with last audits and do the roll back action for each audit till a certain time. So now the question is what the roll back action will be. You can guess that it’s depending on the Audit action of each entity. During rollback:
&lt;ol&gt;
&lt;li&gt;Inserted data will be deleted. 
&lt;li&gt;Deleted data will be inserted. 
&lt;li&gt;Modified data will be replaced by&amp;nbsp;the old one. &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;If we see the conceptual model, our Entity set for Audit was: 
&lt;p&gt;&lt;img border="0" alt="http://www.codeproject.com/KB/database/ImplAudingTrailUsingEFP-2/dbAuditEF.JPG" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003.jpg" width="292" height="428" /&gt;
&lt;p&gt;Here “RevisionStamp” holds the audit insertion date-time, Actions hold the audit action of the entity object (Insert/deleted/modified). Other properties describe themselves with their names. 
&lt;p&gt;So here “Deleted” and “Modified” objects will be rolled back with “Old data” property. And Inserted data will be rolled back with “New data” property.&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;p&gt;&lt;b&gt;Using the Code&lt;/b&gt;
&lt;p&gt;&lt;img border="0" alt="UserDateInput.JPG" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image004.jpg" width="483" height="357" /&gt;
&lt;p&gt;So first, I am going to retrieve all the audits that happen after a specific date-time. This specific date-time is taken from the user. What we have to do is,&amp;nbsp;rollback action for each audit till a specific date and we have to start with the last one (bottom to top). That is why we are going to sort the audit with “RevisionStamp” in a descending order and start doing rollback. 
&lt;p&gt;&amp;nbsp;
&lt;p&gt;public static bool RollBack(DateTime rollBackDate, string userName)
&lt;p&gt;{
&lt;p&gt;using (TransactionScope transactionScope = 
&lt;p&gt;new TransactionScope(System.Transactions.TransactionScopeOption.Required, 
&lt;p&gt;TimeSpan.FromMinutes(30)))
&lt;p&gt;{
&lt;p&gt;AdventureWorksEntities context =new AdventureWorksEntities();
&lt;p&gt;try
&lt;p&gt;{
&lt;p&gt;if (context.Connection.State != ConnectionState.Open)
&lt;p&gt;{&lt;i&gt;//Open the connection&lt;/i&gt;
&lt;p&gt;context.Connection.Open();
&lt;p&gt;}&lt;i&gt;//end if &lt;/i&gt;
&lt;p&gt;&lt;i&gt;//find all audits to roll back&lt;/i&gt;
&lt;p&gt;IEnumerable&amp;lt;DBAudit&amp;gt; auditsToRollBack = DataAdapter.GetEntity
&lt;p&gt;&amp;lt;DBAudit&amp;gt;(context, a =&amp;gt; a.RevisionStamp &amp;gt;= rollBackDate );
&lt;p&gt;if (null != auditsToRollBack &amp;amp;&amp;amp; auditsToRollBack.Count() &amp;gt; 0)
&lt;p&gt;{&lt;i&gt;//if any data found to roll back&lt;/i&gt;
&lt;p&gt;&lt;i&gt;//Order by the audits by creation datetime&lt;/i&gt;
&lt;p&gt;IEnumerable&amp;lt;DBAudit&amp;gt; orderedAudits = 
&lt;p&gt;auditsToRollBack.OrderByDescending(a =&amp;gt; a.RevisionStamp);
&lt;p&gt;foreach (var audit in orderedAudits)
&lt;p&gt;{&lt;i&gt;//iterate each audit &lt;/i&gt;
&lt;p&gt;AuditTrailHelper.DoRollBackAction(ref context, audit, userName);
&lt;p&gt;}&lt;i&gt;//end foreach&lt;/i&gt;
&lt;p&gt;int i =context.SaveChanges();
&lt;p&gt;if (i &amp;gt; 0)
&lt;p&gt;{
&lt;p&gt;transactionScope.Complete();
&lt;p&gt;return true;
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;catch (Exception ex)
&lt;p&gt;{
&lt;p&gt;throw ex;
&lt;p&gt;}
&lt;p&gt;finally
&lt;p&gt;{
&lt;p&gt;&lt;i&gt;// Explicitly dispose of the context, &lt;/i&gt;
&lt;p&gt;&lt;i&gt;// which closes the connection. &lt;/i&gt;
&lt;p&gt;context.Dispose();
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;return false;
&lt;p&gt;}
&lt;p&gt;In DoRollBackAction as I said before, “Deleted” and “Modified” objects will be rolled back with “Old data” property. And Inserted data will be rolled back with “New data” property. 
&lt;p&gt;As I stored old data and new data with XML Serialization while creating the&amp;nbsp;Audit object, I have to deserialise that data into “EntityObject” and do the reverse action according to the audit action.
&lt;p&gt;&amp;nbsp;
&lt;p&gt;private static void DoRollBackAction
&lt;p&gt;(ref AdventureWorksEntities context, DBAudit auditInfo, string userName)
&lt;p&gt;{
&lt;p&gt;if (auditInfo.Actions == AuditTrailHelper.AuditActions.U.ToString() || 
&lt;p&gt;auditInfo.Actions == AuditTrailHelper.AuditActions.D.ToString())
&lt;p&gt;{&lt;i&gt;//For action of Update and Delete&lt;/i&gt;
&lt;p&gt;&lt;i&gt;//Deserialized old data from the XML&lt;/i&gt;
&lt;p&gt;object oldData = AuditTrailHelper.GetAuditObjectFromXML
&lt;p&gt;(auditInfo.OldData, auditInfo.TableName);
&lt;p&gt;if (oldData is EntityObject)
&lt;p&gt;{
&lt;p&gt;EntityObject oldEntity = (EntityObject)oldData;
&lt;p&gt;oldEntity.EntityKey = null;
&lt;p&gt;&lt;i&gt;//add in case of delete or edit the current one with old data &lt;/i&gt;
&lt;p&gt;DataAdapter.EditEntity(ref context, oldEntity);
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;else if (auditInfo.Actions == AuditTrailHelper.AuditActions.I.ToString())
&lt;p&gt;{&lt;i&gt;//For Insert Action&lt;/i&gt;
&lt;p&gt;object newData = AuditTrailHelper.GetAuditObjectFromXML
&lt;p&gt;(auditInfo.NewData, auditInfo.TableName);
&lt;p&gt;if (newData is EntityObject)
&lt;p&gt;{
&lt;p&gt;&lt;i&gt;//Otherwise, delete the entity that has been inserted before&lt;/i&gt;
&lt;p&gt;EntityObject newEntity = (EntityObject)newData;
&lt;p&gt;newEntity.EntityKey = null;
&lt;p&gt;EntityKey key = context.CreateEntityKey
&lt;p&gt;(newEntity.GetType().Name, newEntity);
&lt;p&gt;object objToRemoved = null;
&lt;p&gt;if (context.TryGetObjectByKey(key, out objToRemoved))
&lt;p&gt;{&lt;i&gt;//delete the entity&lt;/i&gt;
&lt;p&gt;context.DeleteObject(objToRemoved);
&lt;p&gt;}&lt;i&gt;//end if &lt;/i&gt;
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;&lt;i&gt;//delete the audit&lt;/i&gt;
&lt;p&gt;context.DeleteObject(auditInfo);
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;After serializing the entity Object, we get the XML string like this:
&lt;p&gt;&amp;nbsp;
&lt;p&gt;&amp;lt;SalesOrderDetail xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
&lt;p&gt;xmlns:xsd=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;gt;
&lt;p&gt;&amp;lt;EntityKey&amp;gt;
&lt;p&gt;&amp;lt;EntitySetName&amp;gt;SalesOrderDetail&amp;lt;/EntitySetName&amp;gt;
&lt;p&gt;&amp;lt;EntityContainerName&amp;gt;AdventureWorksEntities&amp;lt;/EntityContainerName&amp;gt;
&lt;p&gt;&amp;lt;/EntityKey&amp;gt;
&lt;p&gt;&amp;lt;SalesOrderID&amp;gt;1&amp;lt;/SalesOrderID&amp;gt;
&lt;p&gt;&amp;lt;SalesOrderDetailID&amp;gt;0&amp;lt;/SalesOrderDetailID&amp;gt;
&lt;p&gt;&amp;lt;OrderQty&amp;gt;1&amp;lt;/OrderQty&amp;gt;
&lt;p&gt;&amp;lt;UnitPrice&amp;gt;1898.0944&amp;lt;/UnitPrice&amp;gt;
&lt;p&gt;&amp;lt;UnitPriceDiscount&amp;gt;0&amp;lt;/UnitPriceDiscount&amp;gt;
&lt;p&gt;&amp;lt;LineTotal&amp;gt;0&amp;lt;/LineTotal&amp;gt;
&lt;p&gt;&amp;lt;rowguid&amp;gt;6bfaa372-292a-4fd6-84d3-c4e900f09589&amp;lt;/rowguid&amp;gt;
&lt;p&gt;&amp;lt;ModifiedDate&amp;gt;2009-03-26T16:16:41.9691358+06:00&amp;lt;/ModifiedDate&amp;gt;
&lt;p&gt;&amp;lt;SalesOrderHeaderReference /&amp;gt;
&lt;p&gt;&amp;lt;SpecialOfferProductReference&amp;gt;
&lt;p&gt;&amp;lt;EntityKey&amp;gt;
&lt;p&gt;&amp;lt;EntitySetName&amp;gt;SpecialOfferProduct&amp;lt;/EntitySetName&amp;gt;
&lt;p&gt;&amp;lt;EntityContainerName&amp;gt;AdventureWorksEntities&amp;lt;/EntityContainerName&amp;gt;
&lt;p&gt;&amp;lt;EntityKeyValues&amp;gt;
&lt;p&gt;&amp;lt;EntityKeyMember&amp;gt;
&lt;p&gt;&amp;lt;Key&amp;gt;SpecialOfferID&amp;lt;/Key&amp;gt;
&lt;p&gt;&amp;lt;Value xsi:type=&amp;quot;xsd:int&amp;quot;&amp;gt;1&amp;lt;/Value&amp;gt;
&lt;p&gt;&amp;lt;/EntityKeyMember&amp;gt;
&lt;p&gt;&amp;lt;EntityKeyMember&amp;gt;
&lt;p&gt;&amp;lt;Key&amp;gt;ProductID&amp;lt;/Key&amp;gt;
&lt;p&gt;&amp;lt;Value xsi:type=&amp;quot;xsd:int&amp;quot;&amp;gt;777&amp;lt;/Value&amp;gt;
&lt;p&gt;&amp;lt;/EntityKeyMember&amp;gt;
&lt;p&gt;&amp;lt;/EntityKeyValues&amp;gt;
&lt;p&gt;&amp;lt;/EntityKey&amp;gt;
&lt;p&gt;&amp;lt;/SpecialOfferProductReference&amp;gt;
&lt;p&gt;&amp;lt;/SalesOrderDetail&amp;gt;
&lt;p&gt;I have to deserialize this XML string. During deserializing, I have created an XML document and an XML reader using that document. Using that reader, I deserialized the entity object. The method to&amp;nbsp;deserialize&amp;nbsp;the entityobject is: 
&lt;p&gt;&amp;nbsp;
&lt;p&gt;public static object GetAuditObjectFromXML(string ObjectInXML, string typeName)
&lt;p&gt;{
&lt;p&gt;XDocument doc = XDocument.Parse(ObjectInXML);
&lt;p&gt;&lt;i&gt;//Assuming doc is an XML document containing a &lt;/i&gt;
&lt;p&gt;&lt;i&gt;//serialized object and objType is a System.Type set to the type of the object.&lt;/i&gt;
&lt;p&gt;XmlReader reader = doc.CreateReader();
&lt;p&gt;&lt;i&gt;//get the Type of entity object &lt;/i&gt;
&lt;p&gt;Type entityType = Assembly.GetExecutingAssembly().GetType
&lt;p&gt;(&amp;quot;ImplAuditTrailUsingEF.&amp;quot; + typeName);
&lt;p&gt;XmlSerializer ser = new XmlSerializer(entityType);
&lt;p&gt;return ser.Deserialize(reader);
&lt;p&gt;}
&lt;p&gt;For inserting deleted object or to change back modified object, I wrote a single method to edit the object:
&lt;p&gt;&amp;nbsp;
&lt;p&gt;EditEntity(ref AdventureWorksEntities context, EntityObject entity)
&lt;p&gt;Is this method, I change the existence object and attach it to the container otherwise I have inserted the entityObject into the context. To save all of this change, we need an entry in Object state cache.&amp;nbsp; 
&lt;p&gt;&amp;nbsp;
&lt;p&gt;public static void EditEntity
&lt;p&gt;(ref AdventureWorksEntities context, EntityObject entity)
&lt;p&gt;{
&lt;p&gt;&lt;i&gt;// Define an ObjectStateEntry and EntityKey for the current object.&lt;/i&gt;
&lt;p&gt;EntityKey key;
&lt;p&gt;object originalItem;
&lt;p&gt;&lt;i&gt;// Get the detached object&amp;#39;s entity key.&lt;/i&gt;
&lt;p&gt;if (entity.EntityKey == null)
&lt;p&gt;{
&lt;p&gt;&lt;i&gt;// Get the entity key of the updated object.&lt;/i&gt;
&lt;p&gt;key = context.CreateEntityKey(entity.GetType().Name, entity);
&lt;p&gt;}
&lt;p&gt;else
&lt;p&gt;{
&lt;p&gt;key = entity.EntityKey;
&lt;p&gt;}
&lt;p&gt;try
&lt;p&gt;{
&lt;p&gt;&lt;i&gt;// Get the original item based on the entity key from the context&lt;/i&gt;
&lt;p&gt;&lt;i&gt;// or from the database.&lt;/i&gt;
&lt;p&gt;if (context.TryGetObjectByKey(key, out originalItem))
&lt;p&gt;{&lt;i&gt;//accept the changed property&lt;/i&gt;
&lt;p&gt;&lt;i&gt;// Call the ApplyPropertyChanges method to apply changes&lt;/i&gt;
&lt;p&gt;&lt;i&gt;// from the updated item to the original version.&lt;/i&gt;
&lt;p&gt;context.ApplyPropertyChanges(
&lt;p&gt;key.EntitySetName, entity);
&lt;p&gt;}
&lt;p&gt;else
&lt;p&gt;{&lt;i&gt;//add the new entity&lt;/i&gt;
&lt;p&gt;context.AddObject(entity.GetType().Name, entity);
&lt;p&gt;}&lt;i&gt;//end else&lt;/i&gt;
&lt;p&gt;}
&lt;p&gt;catch (System.Data.MissingPrimaryKeyException ex)
&lt;p&gt;{
&lt;p&gt;throw ex;
&lt;p&gt;}
&lt;p&gt;catch (System.Data.MappingException ex)
&lt;p&gt;{
&lt;p&gt;throw ex;
&lt;p&gt;}
&lt;p&gt;catch (System.Data.DataException ex)
&lt;p&gt;{
&lt;p&gt;throw ex;
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;That is all for implementing rollback mechanism in our audit trail. Now all we have to do is just call the “RollBack” method and give it a specific date to roll back. 
&lt;p&gt;&amp;nbsp;
&lt;p&gt;private void btnRollBack_Click(object sender, RoutedEventArgs e)
&lt;p&gt;{
&lt;p&gt;if (AuditTrailHelper.RollBack(dtpRollBackDate.SelectedDate.Value, &amp;quot;Admin&amp;quot;))
&lt;p&gt;{
&lt;p&gt;MessageBox.Show(&amp;quot;Successfully Roll Backed!!&amp;quot;);
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;That’s all for implementation of Audit trial with entity framework. Here I have deleted the audits which have been rolled back. Definitely each rollback operation is also a DB operation and I did an&amp;nbsp;audit for each rollback operation.&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;p&gt;Is the sample project, I have used the free version of Xeed. You may need to download that Library, otherwise you can replace it with the WPF toolkit. It has just been used for getting a date-time from user to rollback.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=197" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author></entry><entry><title>POCO in the Entity Framework - The Experience</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/poco-in-the-entity-framework-part-1-the-experience1.aspx" /><id>/blogs/webdev/archive/2009/05/31/poco-in-the-entity-framework-part-1-the-experience1.aspx</id><published>2009-05-31T02:16:07Z</published><updated>2009-05-31T02:16:07Z</updated><content type="html">&lt;h3&gt;&amp;nbsp;&lt;/h3&gt; &lt;p&gt;Last week I mentioned in the &lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/11/sneak-preview-persistence-ignorance-and-poco-in-entity-framework-4-0.aspx"&gt;sneak preview on POCO&lt;/a&gt; that support for POCO entities is one of the new capabilities we have added to Entity Framework 4.0. This week, I’d like to go into the details of POCO support in Entity Framework 4.0. &lt;p&gt;There’s quite a bit to discuss here, including: &lt;ul&gt; &lt;li&gt;Overall POCO experience in Entity Framework 4.0  &lt;li&gt;Change Tracking in POCO  &lt;li&gt;Relationship Fix-up  &lt;li&gt;Complex Types  &lt;li&gt;Deferred (Lazy) Loading and Explicit Loading  &lt;li&gt;Best Practices&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;In this post, I will focus primarily on the overall experience so that you can get started with POCO in Entity Framework 4.0 right away. I’d like to use a simple example that we can walk through so you can see what it feels like to use POCO in Entity Framework 4.0. I will use the Northwind database, and&amp;nbsp; we’ll continue to build on this example in subsequent posts. &lt;p&gt;&lt;b&gt;Step 1 – Create the Model, turn off default Code Generation&lt;/b&gt; &lt;p&gt;While POCO allows you to write your own entity classes in a persistence ignorant fashion, there is still the need for you to “plug in” persistence and EF metadata so that your POCO entities can be materialized from the database and persisted back to the database. In order to do this, you will still need to either create an Entity Data Model using the Entity Framework Designer or provide the CSDL, SSDL and MSL metadata files exactly as you have done with Entity Framework 3.5. So first I’ll generate an EDMX using the ADO.NET Entity Data Model Wizard. &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb.png" width="495" height="345" /&gt;&lt;/a&gt;  &lt;ol&gt; &lt;li&gt;Create a class library project for defining your POCO types. I named mine &lt;b&gt;NorthwindModel&lt;/b&gt;. This project will be persistence ignorant and will not have a dependency on the Entity Framework.  &lt;li&gt;Create a class library project that will contain your persistence aware code. I named mine &lt;b&gt;NorthwindData. &lt;/b&gt;This project will have a dependency on Entity Framework (System.Data.Entity) in addition to a dependency on the &lt;b&gt;NorthwindModel&lt;/b&gt; project.  &lt;li&gt;&lt;b&gt;Add New Item &lt;/b&gt;to the &lt;b&gt;NorthwindData&lt;/b&gt; project and add an ADO.NET Entity Data Model called &lt;b&gt;Northwind.edmx &lt;/b&gt;(doing this will automatically add the dependency to the Entity Framework).  &lt;li&gt;Go through “Generate from Database” and build a model for the Northwind database.  &lt;li&gt;For now, select &lt;b&gt;Categories&lt;/b&gt; and &lt;b&gt;Products&lt;/b&gt; as the only two tables you are interested in adding to your Entity Data model.&lt;b&gt;&lt;/b&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Now that I have my Entity Data model to work with, there is one final step before I start to write code : turn off code generation. After all you are interested in POCO – so remove the &lt;b&gt;Custom Tool &lt;/b&gt;that is responsible for generating &lt;b&gt;EntityObject&lt;/b&gt; based code for &lt;b&gt;Northwind.edmx. &lt;/b&gt;This will turn off code generation for your model. &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_1.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_1.png" width="505" height="352" /&gt;&lt;/a&gt;  &lt;p&gt;We are now ready to write our POCO entities. &lt;p&gt;&lt;b&gt;Step 2 – Code up your POCO entities&lt;/b&gt; &lt;p&gt;I am going to write simple POCO entities for Category and Product. These will be added to the &lt;b&gt;NorthwindModel&lt;/b&gt; project. Note that what I show here shouldn’t be taken as best practice and the intention here is to demonstrate the simplest case that works out of the box. We will extend and customize this to our needs as we go forward and build on top of this using &lt;b&gt;Repository&lt;/b&gt; and &lt;b&gt;Unit of Work&lt;/b&gt; patterns later on. &lt;p&gt;Here’s sample code for our Category entity:&lt;pre&gt;    public class Category
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
        public string Description { get; set; }
        public byte[] Picture { get; set; }
        public List&amp;lt;Product&amp;gt; Products { get; set; }
    }&lt;/pre&gt;
&lt;p&gt;Note that I have defined properties for scalar properties as well as navigation properties in my model. The Navigation Property in our model translates to a List&amp;lt;Product&amp;gt;.
&lt;p&gt;Similarly, Product entity can be coded like this:&lt;pre&gt;    public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public int SupplierID { get; set; }
        public string QuantityPerUnit { get; set; }
        public decimal UnitPrice { get; set; }
        public Int16 UnitsInStock { get; set; }
        public Int16 UnitsOnOrder { get; set; }
        public Int16 ReorderLevel { get; set; }
        public bool Discontinued { get; set; }
        public Category Category { get; set; }
    }&lt;/pre&gt;
&lt;p&gt;In this case, since the relationship allows only one &lt;b&gt;Category&lt;/b&gt; that a &lt;b&gt;Product&lt;/b&gt; can belong to, we have a reference to a &lt;b&gt;Category&lt;/b&gt; (unlike the &lt;b&gt;List&amp;lt;T&amp;gt;&lt;/b&gt; collection we have for modeling the Navigation Property in &lt;b&gt;Category&lt;/b&gt;).
&lt;p&gt;&lt;b&gt;Step 3 – Code up your Entity Framework Context&lt;/b&gt;
&lt;p&gt;The last thing I have to do in order to pull all of this together is to provide a context implementation (much like the &lt;b&gt;ObjectContext&lt;/b&gt; implementation you get when you use default code generation). The context is the glue that brings persistence awareness into your application, and it will allow you to compose queries, materialize entities as well as save changes back to the database. The context will be a part of the &lt;b&gt;NorthwindData&lt;/b&gt; project.
&lt;p&gt;For simplicity, I will include our context into the same class library that has our entity types – but when we discuss patterns such as &lt;b&gt;Repository &lt;/b&gt;and &lt;b&gt;Unit of Work&lt;/b&gt;, we will set it up such that you have a pure POCO class library without any persistence concerns.
&lt;p&gt;Here’s a simple context implementation for our scenario:&lt;pre&gt;public class NorthwindContext : ObjectContext
    {   
        public NorthwindContext() : base(&amp;quot;name=NorthwindEntities&amp;quot;, &lt;br /&gt;&amp;quot;NorthwindEntities&amp;quot;)  
        {
            _categories = CreateObjectSet&amp;lt;Category&amp;gt;();
            _products = CreateObjectSet&amp;lt;Product&amp;gt;();
        }

        public ObjectSet&amp;lt;Category&amp;gt; Categories
        {
            get 
            { 
                return _categories; 
            }
        }
        private ObjectSet&amp;lt;Category&amp;gt; _categories;

        public ObjectSet&amp;lt;Product&amp;gt; Products
        {
            get
            {
                return _products;
            }
        }
        private ObjectSet&amp;lt;Product&amp;gt; _products;
    }&lt;/pre&gt;
&lt;p&gt;Note that &lt;b&gt;ObjectSet&lt;/b&gt;&amp;lt;&lt;b&gt;T&lt;/b&gt;&amp;gt; is a more specialized &lt;b&gt;ObjectQuery&lt;/b&gt;&amp;lt;&lt;b&gt;T&lt;/b&gt;&amp;gt; that we introduced in Entity Framework 4.0.
&lt;p&gt;That’s it – now you have pure POCO entities with a simple context that will allow you to write queries like this:&lt;pre&gt;    NorthwindContext db = new NorthwindContext();

    var beverages = from p in db.Products
                    where p.Category.CategoryName == &amp;quot;Beverages&amp;quot;
                    select p;&lt;/pre&gt;
&lt;p&gt;The entities that are materialized are pure POCO entities, and you can make and persist changes much like you would with regular &lt;b&gt;EntityObject&lt;/b&gt; or &lt;b&gt;IPOCO&lt;/b&gt; entities. You get all the services provided by Entity Framework - the only difference is that you are using pure POCO entities.
&lt;p&gt;There are many possibilities here as far as how we can improve on this simplified example. Before we get into that however, I would like to get some basic questions out of the way.
&lt;p&gt;&lt;b&gt;Do I need an Entity Data Model before I can use POCO?&lt;/b&gt;
&lt;p&gt;Yes – POCO support in Entity Framework 4.0 simply removes the need of having persistence specific concerns in your entity classes. There is still the need for you to have a CSDL/SSDL/MSL (collectively EDMX) metadata so that the Entity Framework is able to use your entities along with the metadata in order to enable data access. There is a separate effort that we are working on that will allow you to do true “code-first” development without the need to have a predefined EDMX model. A community preview of this feature will be released to the web in the coming months. We will roll this into the product the first chance we get. As always, your feedback will be helpful.
&lt;p&gt;&lt;b&gt;Do I have to always hand-craft these entities and the context?&lt;/b&gt;
&lt;p&gt;No – there is a very powerful and flexible code generation mechanism in Entity Framework 4.0 that is based on T4 as Alex blogged about &lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/19/sneak-peek-using-code-generation-templates-with-the-entity-framework-4-0.aspx"&gt;here&lt;/a&gt;. You can provide your own templates that allow you to build your entities in a way that you see fit. We are also working on providing standard out of the box templates that will generate POCO entities for you.
&lt;p&gt;&lt;b&gt;How is metadata mapped when using POCO entities?&lt;/b&gt;
&lt;p&gt;In Entity Framework 3.5, both &lt;b&gt;EntityObject&lt;/b&gt; and &lt;b&gt;IPOCO&lt;/b&gt; based entities relied on the use of mapping attributes that were meant for decorating and mapping the entity types and properties back to the corresponding elements in the Conceptual model. Entity Framework 4.0 introduces convention based mapping for allowing mapping of Entity Types, Properties, Complex Types and Relationships back to the conceptual model without the need for explicit decoration. The simple rule here is that Entity Type names, Property names and Complex Types names used in your POCO classes must match those defined by the conceptual model. Namespace names are ignored and don’t have to match between the class definition and the conceptual model.
&lt;p&gt;&lt;b&gt;Do I need to have public getters and setters for all properties in my entity classes?&lt;/b&gt;
&lt;p&gt;You can use any access modifier on your POCO type’s properties as long as none of the mapped properties are virtual and as long as you don’t require partial trust support. When running in partial trust, there are specific requirements on the visibility of access modifiers on your entity classes. We will be documenting the complete set of access modifiers that are supported when partial trust is involved.
&lt;p&gt;&lt;b&gt;What types of collections are supported for collection based navigation properties?&lt;/b&gt;
&lt;p&gt;Any collection that is an &lt;b&gt;ICollection&amp;lt;T&amp;gt;&lt;/b&gt; will be supported. If you don’t initialize the field with a concrete type that is an &lt;b&gt;ICollection&amp;lt;T&amp;gt;&lt;/b&gt; type, then an &lt;b&gt;List&amp;lt;T&amp;gt;&lt;/b&gt; type will be provided upon materialization.
&lt;p&gt;&lt;b&gt;Can I have uni-directional relationships? For instance – I would like to have a Category property in my Product class, but I don’t want to have a Products collection in my Category class.&lt;/b&gt;
&lt;p&gt;Yes – this is supported. The only restriction here is that your entity types have to reflect what is defined by the model. If you are not interested in having the navigation property for one side of the relationship, then remove it from the model completely.
&lt;p&gt;&lt;b&gt;Is Deferred (Lazy) Loading supported with POCO?&lt;/b&gt;
&lt;p&gt;Yes – Deferred (Lazy) loading is supported with POCO through the use of proxy types that are used to provide automatic lazy loading behavior on top of your POCO classes. This is something that we’ll cover when we get to deferred loading – until then know that eager loading via the use of “&lt;b&gt;Include&lt;/b&gt;” is also supported, like so:&lt;pre&gt;var beverageCategory = (from c in context.Categories&lt;br /&gt;.Include(&amp;quot;Products&amp;quot;)
                        where c.CategoryName == &amp;quot;Beverages&amp;quot;
                        select c).Single();&lt;/pre&gt;
&lt;p&gt;If I were to use Deferred (Lazy) Loading, I don’t have to do this – we’ll discuss that when we discuss proxies.
&lt;h6&gt;Fixing up Relationships&lt;/h6&gt;
&lt;p&gt;There are two types of fix-ups to be aware of: 1)Fix-up during query, and 2) Fix-up during changes to your entities/relationships
&lt;p&gt;&lt;b&gt;&lt;u&gt;Fix-up during Query&lt;/u&gt;&lt;/b&gt;&lt;u&gt; &lt;/u&gt;
&lt;p&gt;Fix-up during query happens when you load related entities using separate queries on the same &lt;b&gt;ObjectContext&lt;/b&gt;. For instance, if I were to query for a category instance &lt;b&gt;Beverages&lt;/b&gt;, and later query for a product instance &lt;b&gt;Chai&lt;/b&gt; (that is in Category &lt;b&gt;Beverages&lt;/b&gt;), I would want &lt;b&gt;chai.Category&lt;/b&gt; to point to the instance of the &lt;b&gt;Beverages&lt;/b&gt; category without additional work.
&lt;p&gt;This is automatic and works today.
&lt;p&gt;&lt;b&gt;&lt;u&gt;Fix-up during changes to your entities/relationships&lt;/u&gt;&lt;/b&gt;
&lt;p&gt;This is the relationship fix-up between two entities when I add/remove an entity that is related to another entity or alter relationships. Think of this as the case when I create a new product called &lt;b&gt;“Diet Chai”&lt;/b&gt; and want to associate it with the &lt;b&gt;Beverages &lt;/b&gt;category&lt;b&gt;.&lt;/b&gt;
&lt;p&gt;In Beta1 of Entity Framework 4.0, you do not get automatic relationship fix-up in this case with POCO entities. When dealing with relationships that change between entities, you will have to make sure that your POCO types include the logic to manage fix-up on both ends of the relationship correctly. 
&lt;p&gt;For instance, in my Northwind example, I have defined the following method on &lt;b&gt;Category&lt;/b&gt; to support adding / removing of Orders.&lt;pre&gt;        public void AddProduct(Product p)
        {
            if (Products == null)
            {
                Products = new List&amp;lt;Product&amp;gt;();
            }

            if (!Products.Contains(p))
            {
                Products.Add(p);
            }            
            
            p.Category = this;
        }&lt;/pre&gt;
&lt;p&gt;In general, it is good to use a pattern like this to support adding/removing related items rather than using the relationship collection to add/remove related entities. You also have options of making the getter/setter for the actual EF backed collection private/internal to support more fine grained access – but as mentioned earlier, some of this depends on the requirements as to whether you require partial trust support or not.
&lt;p&gt;So we have covered quite a bit of ground in this “quick look” at the overall POCO experience. There’s quite a lot more to talk about – and I will be continuing this discussion early next week. In the meantime, take a look at the complete solution (attached) if you are interested in the sample code covering all the concepts we covered here. Please keep in mind that you must have a local instance of Northwind database installed on the machine where you are running this sample.
&lt;p&gt;In my next post we will look at Complex Types, Change Tracking, Proxies, Lazy Loading and Eager Loading. Until then, please look through the MSDN Documentation on POCO &lt;a href="http://msdn.microsoft.com/en-us/library/dd456853(VS.100).aspx"&gt;here&lt;/a&gt; for more details on POCO support in Entity Framework 4.0.
&lt;p&gt;Let us know what you think!
&lt;p&gt;Faisal Mohamood &lt;br /&gt;Program Manager, Entity Framework
&lt;p&gt;Filed under: &lt;a href="http://blogs.msdn.com/adonet/archive/tags/Entity+Framework/default.aspx"&gt;Entity Framework&lt;/a&gt;
&lt;p&gt;Attachment(s):&amp;nbsp;&lt;a href="http://blogs.msdn.com/adonet/attachment/9634552.ashx"&gt;NorthwindPocoSamplePart1.zip&lt;/a&gt;
&lt;p&gt;&amp;nbsp;
&lt;h3&gt;Complex Types, Deferred Loading and Explicit Loading&lt;/h3&gt;
&lt;p&gt;Published 28 May 09 09:03 AM | &lt;a href="http://blogs.msdn.com/user/Profile.aspx?UserID=27139"&gt;dpblogs&lt;/a&gt;
&lt;p&gt;In my post last week on the &lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/21/poco-in-the-entity-framework-part-1-the-experience.aspx"&gt;POCO Experience in Entity Framework&lt;/a&gt;, I covered the fundamentals of POCO support in Entity Framework 4.0. In this post, I’ll cover a few more aspects related to POCO.
&lt;h6&gt;Complex Types&lt;/h6&gt;
&lt;p&gt;Complex Types are supported in POCO just like they are with regular &lt;b&gt;EntityObject&lt;/b&gt; based entities. All you have to do is declare your complex types as POCO classes and then use them for declaring the complex type based properties on your POCO entities.
&lt;p&gt;As an example, here’s an &lt;b&gt;InventoryDetail&lt;/b&gt; complex type to represent a part of my Product entity:&lt;pre&gt;public class InventoryDetail&lt;br /&gt;{&lt;br /&gt;    public Int16 UnitsInStock { get; set; }&lt;br /&gt;    public Int16 UnitsOnOrder { get; set; }&lt;br /&gt;    public Int16 ReorderLevel { get; set; }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;My &lt;b&gt;Product&lt;/b&gt; class now has been modified to include a property of this type to group the inventory detail fields:&lt;pre&gt;public class Product&lt;br /&gt;{&lt;br /&gt;    public int ProductID { get; set; }&lt;br /&gt;    public string ProductName { get; set; }&lt;br /&gt;    public int SupplierID { get; set; }&lt;br /&gt;    public string QuantityPerUnit { get; set; }&lt;br /&gt;    public decimal UnitPrice { get; set; }&lt;br /&gt;    public InventoryDetail InventoryDetail { get; set; }&lt;br /&gt;    public bool Discontinued { get; set; }&lt;br /&gt;    public Category Category { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;You can then do everything you are used to doing with Complex Types. Here’s how I use it in a query:&lt;pre&gt;var outOfStockProducts = from c in context.Products&lt;br /&gt;                         where c.InventoryDetail.UnitsInStock == 0&lt;br /&gt;                         select c;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, Complex Type support with POCO is really straightforward to use. There are a couple of things you need to keep in mind when using complex types support with POCO:
&lt;ol&gt;
&lt;li&gt;You must define your Complex Type as a class. Structs are not supported. 
&lt;li&gt;You cannot use inheritance with your complex type classes.&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;While we are on the topic of Complex Types, I thought I’d mention one other thing: Did you know that the Entity Framework designer in Visual Studio 2010 supports complex type declarations? 
&lt;p&gt;In Visual Studio 2008, you had to manually add the Complex Type declaration to the CSDL. That is all history with the Complex Type support in the designer in Visual Studio 2010.
&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_3.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_3.png" width="495" height="365" /&gt;&lt;/a&gt; 
&lt;p&gt;And what’s cool is that because Visual Studio 2010 supports Multi-Targeting, you can use this capability when building applications that target .NET Framework 3.5, using Entity Framework 3.5 as well!
&lt;h6&gt;Deferred/Lazy Loading&lt;/h6&gt;
&lt;p&gt;In my &lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/12/sneak-preview-deferred-loading-in-entity-framework-4-0.aspx"&gt;sneak preview post on Deferred Loading&lt;/a&gt; two weeks ago, I mentioned that there is now Deferred Loading support in Entity Framework. It comes as no surprise then that the default code-generated entity types out of the box based on &lt;b&gt;EntityObject&lt;/b&gt; will offer Deferred Loading. If you are wondering whether Deferred Loading is supported with POCO objects, then I think you will be happy to know that you can get Deferred Loading with POCO as well.
&lt;p&gt;There are two things you need to do in order to get Deferred Loading support with POCO entities:
&lt;ol&gt;
&lt;li&gt;Declare the property that you would like to load lazily as &lt;b&gt;virtual. &lt;/b&gt;These properties can be any collection type that implements &lt;b&gt;ICollection&amp;lt;T&amp;gt; &lt;/b&gt;or they can be a reference representing a 1/0..1 relationship.&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;For instance, here’s a part of the updated &lt;b&gt;Category&lt;/b&gt; entity class which I have modified to support Deferred Loading:&lt;pre&gt;public class Category&lt;br /&gt;{&lt;br /&gt;    public int CategoryID { get; set; }&lt;br /&gt;    public string CategoryName { get; set; }&lt;br /&gt;    public string Description { get; set; }&lt;br /&gt;    public byte[] Picture { get; set; }&lt;br /&gt;    public virtual List&amp;lt;Product&amp;gt; Products { get; set; }&lt;br /&gt;    ...&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.&amp;nbsp;&amp;nbsp; Enable deferred loading on the context: &lt;pre&gt;context.ContextOptions.DeferredLoadingEnabled = true;&lt;/pre&gt;
&lt;p&gt;That’s it. You will now get automatic Deferred Loading for your POCO types without having to do anything else.
&lt;p&gt;&lt;b&gt;So how exactly does this work and what’s going on under the covers? &lt;/b&gt;
&lt;p&gt;The reason why this works is because when I marked my collection property as &lt;b&gt;virtual&lt;/b&gt;, this allowed the Entity Framework to provide a &lt;b&gt;proxy&lt;/b&gt; instance for my POCO type at runtime, and it is this proxy that does automatic deferred loading. The proxy instance is based on a type that derives from my own POCO entity class - so all functionality you have provided is preserved. From a developer point of view, this allows you to write persistence ignorant code even when deferred loading might be a requirement.
&lt;p&gt;If you were to inspect the actual instance in the debugger, you will see that the underlying type for the instance is different from the original type that I declared:
&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_2.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_2.png" width="496" height="183" /&gt;&lt;/a&gt; 
&lt;p&gt;While the Entity Framework does its best to provide automatic deferred loading with minimal friction, this is something you need to be aware of when dealing with manual creation of instances that you want to then add or attach, or when you serialize/deserialize instances.
&lt;p&gt;&lt;b&gt;&lt;u&gt;Manual instantiation of Proxy instances for POCO entities&lt;/u&gt;&lt;/b&gt;
&lt;p&gt;In order to enable creation of proxy instances for adding/attaching, you can use the CreateObject factory method on ObjectContext for creating entity instances:&lt;pre&gt;Category category = context.CreateObject&amp;lt;Category&amp;gt;();&lt;/pre&gt;
&lt;p&gt;Try to keep this in mind and use &lt;b&gt;CreateObject&lt;/b&gt; when creating instances that you want to then use with the Entity Framework.
&lt;h6&gt;More Efficient Change Tracking with “Change Tracking Proxies”&lt;/h6&gt;
&lt;p&gt;The standard POCO entities we have talked about until now rely on snapshot based change tracking – i.e. the Entity Framework will maintain snapshots of before values and relationships of the entities so that they can be compared with current values later during Save. However, this comparison is relatively expensive when compared to the way change tracking works with EntityObject based entities. 
&lt;p&gt;There is another type of proxy that will allow you to get better performance out of change tracking with POCO entities.
&lt;p&gt;If you are familiar with IPOCO, you know that &lt;b&gt;IEntityWithChangeTracker &lt;/b&gt;was one of the interfaces you were required to implement to provide change notifications to the Entity Framework.
&lt;p&gt;&lt;b&gt;Change Tracking proxies &lt;/b&gt;subclass your POCO entity class to provide you with this capability during runtime without requiring you to implement the IPOCO interfaces yourself. 
&lt;p&gt;In many ways, you get the best of both worlds with this approach: You get persistence ignorance with POCO classes and you get the performance of &lt;b&gt;EntityObject&lt;/b&gt; / &lt;b&gt;IPOCO&lt;/b&gt; when it comes to change tracking. 
&lt;p&gt;To get change tracking proxies, the basic rule is that your class must be public, non-abstract or non-sealed. Your class must also implement public virtual getters/setters for all properties that are persisted. Finally, you must declare collection based relationship navigation properties as ICollection&amp;lt;T&amp;gt; only. They cannot be a concrete implementation or another interface that derives from ICollection&amp;lt;T&amp;gt; (a difference from the Deferred Loading proxy)
&lt;p&gt;Here’s an example of my POCO class for &lt;b&gt;Product&lt;/b&gt; that will give me more efficient proxy based change tracking at runtime:&lt;pre&gt;public class Product&lt;br /&gt;{&lt;br /&gt;    public virtual int ProductID { get; set; }&lt;br /&gt;    public virtual string ProductName { get; set; }&lt;br /&gt;    public virtual int SupplierID { get; set; }&lt;br /&gt;    public virtual string QuantityPerUnit { get; set; }&lt;br /&gt;    public virtual decimal UnitPrice { get; set; }&lt;br /&gt;    public virtual InventoryDetail InventoryDetail { get; set; }&lt;br /&gt;    public virtual bool Discontinued { get; set; }&lt;br /&gt;    public virtual Category Category { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Once again, keep in mind that you must use &lt;b&gt;CreateObject &lt;/b&gt;for creating proxy instances you want to then add or attach to the context. But pure POCO entities that don’t rely on proxies and proxy based entities can work together. You need to only use CreateObject when dealing with proxy based entities.
&lt;p&gt;&lt;b&gt;What if I want both Deferred Loading and better change tracking for the same POCO type?&lt;/b&gt;
&lt;p&gt;The two are not mutually exclusive and you don’t have to choose between a Deferred Loading proxy and a Change Tracking proxy. If you want Deferred Loading and efficient change tracking, you just have to follow the rules for Change Tracking via proxies, and enable Deferred Loading. Change Tracking proxies will give you deferred loading if deferred loading is enabled.
&lt;h6&gt;Explicit Loading&lt;/h6&gt;
&lt;p&gt;All this deferred loading capability is great – but there are plenty of you out there that want to be in full control of how you load related entities. You might even choose to go the route of pure POCO without having to resort to any of the automatic proxy generation done for you.
&lt;p&gt;This is a perfectly acceptable (and preferable in many cases) and you can use explicit loading of relationships and be in complete control of how you query for data from the database.
&lt;p&gt;There are two options for doing &lt;b&gt;Explicit Load&lt;/b&gt; with POCO:
&lt;p&gt;One is to use &lt;b&gt;ObjectContext.LoadProperty &lt;/b&gt;and specify the name of the navigation property you want to load:&lt;pre&gt;context.LoadProperty(beveragesCategory, &amp;quot;Products&amp;quot;);&lt;/pre&gt;
&lt;p&gt;This gets the job done – but it isn’t very type safe as you can see. If I don’t have the right name of the navigation property here, I will get a runtime exception.
&lt;p&gt;Some of you might actually prefer this:&lt;pre&gt;context.LoadProperty(beveragesCategory, c =&amp;gt; c.Products);&lt;/pre&gt;
&lt;p&gt;I can use a lambda expression to specify the property that I want to load explicitly, and this is offers more type safety.
&lt;p&gt;So that’s about everything I planned on covering in the second post. There’s more to come however – in the final part of this series, we’ll go over some of the things to be aware of when dealing with pure POCO (non proxy) instances and keeping things in sync between your object graph and the Object State Manager. We will also cover variations of SaveChanges that you might want to be aware of.
&lt;p&gt;In the meantime, check out the sample code that I have updated to cover some of the things we have talked about in this post.
&lt;p&gt;Faisal Mohamood &lt;br /&gt;Program Manager, Entity Framework
&lt;p&gt;Filed under: &lt;a href="http://blogs.msdn.com/adonet/archive/tags/ADO.NET/default.aspx"&gt;ADO.NET&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/adonet/archive/tags/Entity+Framework/default.aspx"&gt;Entity Framework&lt;/a&gt;
&lt;p&gt;Attachment(s):&amp;nbsp;&lt;a href="http://blogs.msdn.com/adonet/attachment/9647609.ashx"&gt;NorthwindPocoSamplePart2.zip&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=196" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author><category term="Entity Framework" scheme="http://community.icburner.com/blogs/webdev/archive/tags/Entity+Framework/default.aspx" /><category term="POCO" scheme="http://community.icburner.com/blogs/webdev/archive/tags/POCO/default.aspx" /></entry><entry><title>Updated Entity Framework Documentation for Beta1</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/updated-entity-framework-documentation-for-beta1.aspx" /><id>/blogs/webdev/archive/2009/05/31/updated-entity-framework-documentation-for-beta1.aspx</id><published>2009-05-31T02:12:25Z</published><updated>2009-05-31T02:12:25Z</updated><content type="html">&lt;p&gt;With the release of &lt;a href="http://go.microsoft.com/fwlink/?LinkId=152517"&gt;Visual Studio 2010 Beta 1&lt;/a&gt;, we have released supporting &lt;a href="http://msdn.microsoft.com/en-us/library/bb399572(VS.100).aspx"&gt;Entity Framework documentation&lt;/a&gt;. Below are links to documentation for new Entity Framework features and scenarios. Along with feedback on the Entity Framework, we would like to hear your feedback on the documentation. What works for you? What doesn’t? What’s missing? We’ll work to incorporate your feedback in future releases. &lt;p&gt;Thanks! &lt;p&gt;&lt;i&gt;Entity Framework User Education Team&lt;/i&gt; &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Persistence-Ignorant Objects&lt;/b&gt; &lt;p&gt;You can use your own custom data classes together with your data model without making any modifications to the data classes themselves. This means that you can use &amp;quot;plain old&amp;quot; CLR objects (POCO), such as existing domain objects, with your Entity Framework application. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/dd456853(VS.100).aspx"&gt;Persistence Ignorant Objects (Entity Framework)&lt;/a&gt;. &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Deferred Loading of Related Objects&lt;/b&gt; &lt;p&gt;With deferred loading, also known as &lt;i&gt;lazy loading&lt;/i&gt;, related objects are automatically loaded from the data source when you access a navigation property. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb896272(VS.100).aspx"&gt;Shaping Query Results (Entity Framework)&lt;/a&gt;. &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Functions in LINQ to Entities Queries&lt;/b&gt; &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.entityfunctions(VS.100).aspx"&gt;EntityFunctions&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions(VS.100).aspx"&gt;SqlFunctions&lt;/a&gt; classes provide access to canonical and database functions from LINQ to Entities queries. The &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.objects.dataclasses.edmfunctionattribute(VS.100).aspx"&gt;EdmFunctionAttribute&lt;/a&gt; allows a CLR method to serve as a proxy for a function defined in the conceptual model or storage model. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/dd456828(VS.100).aspx"&gt;Calling Functions in LINQ to Entities Queries&lt;/a&gt;.  &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Customized Object Layer Code Generation&lt;/b&gt; &lt;p&gt;You can configure the &lt;a href="http://msdn.microsoft.com/en-us/library/cc716685(VS.100).aspx"&gt;ADO.NET Entity Data Model Designer&lt;/a&gt; to use text templates to generate customized object layer code. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/dd456821(VS.100).aspx"&gt;How to: Customize Object Layer Code Generation&lt;/a&gt;. &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Model-First Support&lt;/b&gt; &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/dd456817(VS.100).aspx"&gt;Create Database Wizard&lt;/a&gt; enables you to do conceptual modeling first, and then create a database that supports the model. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/dd456815(VS.100).aspx"&gt;How to: Generate a Database from a Conceptual Model&lt;/a&gt;. &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Complex Type Support in the Entity Data Model Designer&lt;/b&gt; &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/cc716685(VS.100).aspx"&gt;ADO.NET Entity Data Model Designer&lt;/a&gt; now supports complex types. For more information, see the following topics: &lt;ul&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd456820(VS.100).aspx"&gt;How to: Create and Modify Complex Types&lt;/a&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd456823(VS.100).aspx"&gt;How to: Add a Complex Type to an Entity Type&lt;/a&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd456824(VS.100).aspx"&gt;How to: Map a Function Import to a Complex Type&lt;/a&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd456822(VS.100).aspx"&gt;How to: Map Complex Type Properties to Table Columns&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Naming Service&lt;/b&gt; &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/bb399247(VS.100).aspx"&gt;Entity Data Model Wizard&lt;/a&gt; and the &lt;a href="http://msdn.microsoft.com/en-us/library/cc716705(VS.100).aspx"&gt;Update Model Wizard&lt;/a&gt; provide the option of using singular or plural forms of &lt;b&gt;Entity&lt;/b&gt;, &lt;b&gt;EntitySet&lt;/b&gt;, and &lt;b&gt;NavigationProperty&lt;/b&gt; names to make application code more readable. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb399253(VS.100).aspx"&gt;Choose Your Database Objects Dialog Box (Entity Data Model Wizard)&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/cc716689(VS.100).aspx"&gt;Choose Your Database Objects Dialog Box (Update Model Wizard)&lt;/a&gt;. &lt;p&gt;&lt;b&gt;&lt;/b&gt; &lt;p&gt;&lt;b&gt;Improved Model Browser Functionality&lt;/b&gt; &lt;p&gt;The &lt;b&gt;Model Browser&lt;/b&gt; window of the &lt;a href="http://msdn.microsoft.com/en-us/library/cc716685(VS.100).aspx"&gt;ADO.NET Entity Data Model Designer&lt;/a&gt; enables you to delete objects from the storage model and to search the conceptual and storage models for a specified string. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb738483(VS.100).aspx"&gt;Model Browser Window&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/dd456816(VS.100).aspx"&gt;How to: Delete Objects from the Storage Model&lt;/a&gt;. &lt;p&gt;&lt;b&gt;User-Defined Functions (Entity SQL)&lt;/b&gt; &lt;p&gt;Entity SQL supports calling user-defined functions in a query. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/dd490950(VS.100).aspx"&gt;User-Defined Functions (Entity SQL)&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=195" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author></entry><entry><title>Better N-Tier Concurrency Management for the Entity Framework(Sum)</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/better-n-tier-concurrency-management-for-the-entity-framework-sum.aspx" /><id>/blogs/webdev/archive/2009/05/31/better-n-tier-concurrency-management-for-the-entity-framework-sum.aspx</id><published>2009-05-30T17:17:07Z</published><updated>2009-05-30T17:17:07Z</updated><content type="html">&lt;h4&gt;&lt;a href="http://blog.tonysneed.com/?p=120"&gt;Better N-Tier Concurrency Management for the Entity Framework&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;Posted in &lt;a href="http://blog.tonysneed.com/?cat=2"&gt;Technical&lt;/a&gt; at 11:03 am by Tony &lt;p&gt;I just wrote an article for MSDN Magazine (due out in December) about developing n-tier applications for both LINQ to SQL and the Entity Framework. While researching the topic, I noticed a certain awkwardness with the Entity Framework API when it came to managing concurrency with a timestamp fields, as compared with LINQ to SQL. L2S has an overloaded &lt;b&gt;Attach&lt;/b&gt; method that accepts a bool &lt;i&gt;asModified&lt;/i&gt; parameter indicating the presence of a timestamp field used for concurrency. The Entity Framework, on the other hand, requires attaching the original &lt;i&gt;unmodified&lt;/i&gt; entity, then calling &lt;b&gt;ApplyAllChanges&lt;/b&gt;, passing in the modified entity. This doesn’t make a whole lot of sense when using a timestamp for concurrency checking, because the only original value you care about is the timestamp, which is passed in unchanged as part of the modified entity. Using timestamps is a great idea because it relieves the client from needing to cache the object’s original values and reduces the amount of data sent over the wire when you’re sending entities to a service for persistence. In the article, I got around this by querying the database from the service using the key value of the modified entity. Yuck! &lt;p&gt;Before you throw up your hands in despair, I have good news for you. Danny Simmons, a developer and program manager on the EF team, just came up with a couple &lt;a href="http://blogs.msdn.com/dsimmons/archive/2008/10/31/attachasmodified-a-small-step-toward-simplifying-ef-n-tier-patterns.aspx"&gt;extension methods&lt;/a&gt; to obviate the need for original entity values. Rather than taking the original entity and applying property changes from a detached object that has been modified, you can simply take the detached object and set the state of each property to modified. What you’re essentially saying is, “Look, I already have a modified entity, just change the state of each property from ‘Unchanged’ to ‘Modified’ so that when I call &lt;b&gt;SaveChanges&lt;/b&gt; the updates are persisted.” &lt;p&gt;There’s one more wrinkle to this scenario: using Data Transfer Objects (DTOs) instead of EF entities in the Data Access Layer (DAL). Although v.2 of the Entity Framework will allow you to use DTOs directly as EF entities, this is not yet fully supported in v.1, meaning that an UpdateOrder method would accept a DTO.Order object, which you would use to create an L2E.Order object. To accomplish this, I created an extension method for &lt;b&gt;ObjectContext&lt;/b&gt; called &lt;b&gt;CreateEntityFromObject&lt;/b&gt; which accepts a DTO and uses reflection to copy properties from the DTO to the Entity and create an EntityKey. The code to persist changes to an Order entity now looks like this: &lt;p&gt;static DTO.Order UpdateOrder(DTO.Order order) &lt;p&gt;{ &lt;p&gt;using (NorthwindEntities db = new NorthwindEntities()) &lt;p&gt;{ &lt;p&gt;// Create new order entity from DTO.Order &lt;p&gt;Order updatedOrder = db.&lt;b&gt;CreateEntityFromObject&lt;/b&gt; &lt;p&gt;&amp;lt;Order&amp;gt;(&amp;quot;OrderSet&amp;quot;, order); &lt;p&gt;// Attach modified order (with original timestamp) &lt;p&gt;db.&lt;b&gt;AttachAsModified&lt;/b&gt;(updatedOrder); &lt;p&gt;try &lt;p&gt;{ &lt;p&gt;db.SaveChanges(); &lt;p&gt;} &lt;p&gt;catch (OptimisticConcurrencyException conflictEx) &lt;p&gt;{ &lt;p&gt;Console.WriteLine(conflictEx.Message); &lt;p&gt;return null; &lt;p&gt;} &lt;p&gt;return GetOrder(order.OrderID); &lt;p&gt;} &lt;p&gt;} &lt;p&gt;Here is the CreateEntityFromObject extension method: &lt;p&gt;public static TEntity CreateEntityFromObject&amp;lt;TEntity&amp;gt; &lt;p&gt;(this ObjectContext context, &lt;p&gt;string entitySetName, object dto) &lt;p&gt;where TEntity : IEntityWithKey, new() &lt;p&gt;{ &lt;p&gt;// Create a new entity &lt;p&gt;TEntity entity = new TEntity(); &lt;p&gt;// Copy properties &lt;p&gt;foreach (PropertyInfo dtoProp in dto.GetType().GetProperties()) &lt;p&gt;{ &lt;p&gt;PropertyInfo entityProp = typeof(TEntity).GetProperty(dtoProp.Name); &lt;p&gt;object propValue = dtoProp.GetValue(dto, null); &lt;p&gt;entityProp.SetValue(entity, propValue, null); &lt;p&gt;} &lt;p&gt;// Set the entity key &lt;p&gt;entity.EntityKey = context.CreateEntityKey(entitySetName, entity); &lt;p&gt;// Return the entity &lt;p&gt;return entity; &lt;p&gt;} &lt;p&gt;To see all of this in action, you can download the code for my &lt;a href="http://tonysneed.com/wni3/download/ConcurrencyTest.zip"&gt;sample concurrency application&lt;/a&gt;. Enjoy! &lt;p&gt;12.11.08 &lt;h4&gt;&lt;a href="http://blog.tonysneed.com/?p=140"&gt;Bug in EF v.1 Limits N-Tier Scenarios&lt;/a&gt;&lt;/h4&gt; &lt;p&gt;Posted in &lt;a href="http://blog.tonysneed.com/?cat=2"&gt;Technical&lt;/a&gt; at 8:02 am by Tony &lt;p&gt;About a month ago I wrote a &lt;a href="http://blog.tonysneed.com/?p=120"&gt;blog post&lt;/a&gt; on an extension method for the Entity Framework called AttachAsModified, which was offered by &lt;a href="http://blogs.msdn.com/dsimmons/archive/2008/10/31/attachasmodified-a-small-step-toward-simplifying-ef-n-tier-patterns.aspx"&gt;Danny Simmons&lt;/a&gt; shortly after PDC as a way to perform disconnected updates from an n-tier service. Unfortunately, I discovered what I consider to be a bug in EF v.1 that limits your ability to use the &lt;b&gt;AttachAsModified&lt;/b&gt; extension method. The problem surfaces when the entity you’re trying to update has reference properties to related entities. For example, say you have an Order entity with a Customer navigation property that relates it to the Customer entity. If Order contained a CustomerID property representing the foreign key, you could simply set its value. But the EF models this as an association between Order and Customer and does not include CustomerID as a foreign key in the Order entity. (The EF team, nevertheless, is considering allowing &lt;a href="http://blogs.msdn.com/efdesign/archive/2008/10/27/foreign-keys-in-the-conceptual-and-object-models.aspx"&gt;foreign keys&lt;/a&gt; into the model.) &lt;p&gt;The way to set reference properties in EF is to set the &lt;b&gt;EntityKey&lt;/b&gt; of the &lt;i&gt;reference&lt;/i&gt; property to a new key based on the foreign key value you want to set it to. For example, if you want to change the Customer that an Order is associated with, you need to do the following: &lt;p&gt;updatedOrder.CustomerReference.EntityKey = &lt;p&gt;new EntityKey(&amp;quot;NorthwindEntities.CustomerSet&amp;quot;, &lt;p&gt;&amp;quot;CustomerID&amp;quot;, newCustomerID); &lt;p&gt;The problem is that, when you call &lt;b&gt;SaveChanges&lt;/b&gt; on the &lt;b&gt;ObjectContext&lt;/b&gt;, EF includes the non-reference &lt;b&gt;Customer&lt;/b&gt; property in the WHERE clause of the UPDATE statement. &lt;p&gt;exec sp_executesql &lt;p&gt;N&amp;#39;update [dbo].[Orders] &lt;p&gt;set [CustomerID] = @0, &lt;p&gt;[OrderDate] = @1, &lt;p&gt;-- other fields set to null &lt;p&gt;&lt;b&gt;where (([&lt;/b&gt;&lt;b&gt;CustomerID&lt;/b&gt;&lt;b&gt;] &lt;/b&gt;&lt;b&gt;is null&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;and ([OrderID] = @2))&lt;/b&gt; &lt;p&gt;&lt;b&gt;and ([RowVersion] = @3))&lt;/b&gt; &lt;p&gt;N&amp;#39;@0 nchar(5),@1 datetime,@2 int,@3 binary(8)&amp;#39;, &lt;p&gt;@0=N&amp;#39;ANATR&amp;#39;,@1=&amp;#39;1996-09-29 00:00:00:000&amp;#39;,@2=10308,@3=0x000000000004BF3D &lt;p&gt;If you leave it null, or set it to anything other than the original value, this will result in an &lt;b&gt;OptimisticConcurrencyException&lt;/b&gt;. This means you are required to pass in the Order’s original CustomerID value, which doesn’t make sense if you are using a timestamp column to manage concurrency (which is the purpose of the [RowVersion] in the above WHERE clause. &lt;p&gt;For this reason, I can’t bring myself to require the client app to retain original foreign key values, and I’m left having to re-query the database for the original entity, then set the timestamp property to that passed in with the updated entity. After detaching the entity to commit this change and mark it as ‘unmodified’, you can then modify the original entity properties to the values of the updated entity and call &lt;b&gt;SaveChanges&lt;/b&gt;. While re-querying the database for the original entity isn’t pretty (and quite inefficient), I think it’s a better alternative to passing in the original values from the client (an approach advocated by MS architect &lt;a&gt;Cesar de la Torre&lt;/a&gt;), because it won’t require code changes in the client when the EF team fixes the bug (hopefully before the release of v. 2!). &lt;p&gt;Here is a &lt;a href="http://tonysneed.com/elinq/download/EF-Bug.zip"&gt;sample app&lt;/a&gt; that demonstrates the bug and also how to avoid it by re-querying the database. Cheers. &lt;h4&gt;&lt;a&gt;&lt;/a&gt;Updating data using Entity Framework in N-Tier and N-Layer Applications (short lived EF contexts) - (Part 1) &lt;/h4&gt; &lt;p&gt;First of all, we are talking about using &lt;b&gt;Entity Framework&lt;/b&gt; and how it fits within &lt;b&gt;N-Tier&lt;/b&gt; and &lt;b&gt;N-Layer&lt;/b&gt; applications, ok?, that’s our initial scenario. &lt;p&gt;An &lt;b&gt;N-Tier application&lt;/b&gt; is an application where you have 3 or more &lt;u&gt;physical tiers&lt;/u&gt;. I mean with that things like, “Presentation/Client Tier”, “Application/Business Server Tier” and “Data Tier” (a database server in most of the cases) and nowadays we use web services (or even better, WCF Services) to communicate between presentation tier and the application server tier. Here you see a simple &amp;amp; typical picture about &lt;b&gt;N-Tier architecture&lt;/b&gt;: &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/cesardelatorre/WindowsLiveWriter/UpdatingdatausingEntityFrameworkinNTiera_9B49/clip_image002_2.jpg"&gt;&lt;img border="0" alt="clip_image002" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image001.jpg" width="581" height="264" /&gt;&lt;/a&gt; &lt;p&gt;As you can see, all the client applications (we could be for instance &lt;b&gt;WinForms&lt;/b&gt;, &lt;b&gt;WPF&lt;/b&gt;, or even &lt;b&gt;Silverlight&lt;/b&gt; apps) need to remotely access to the application Server tier using for example &lt;b&gt;WCF Services&lt;/b&gt;. &lt;p&gt;Also, in my opinion. &lt;strong&gt;RIA&lt;/strong&gt; (&lt;strong&gt;&lt;i&gt;Rich Internet Applications&lt;/i&gt;&lt;/strong&gt;) is a special subset of N-Tier apps. &lt;p&gt;A different matter is that we’d probably design our application as an &lt;b&gt;&lt;i&gt;N-Layer&lt;/i&gt;&lt;/b&gt; application, I mean, with several logic layers where we implement different logic tasks. For example we could have the &lt;b&gt;DAL layer&lt;/b&gt; (&lt;i&gt;Data Access Layer&lt;/i&gt;), &lt;b&gt;BLL Layer&lt;/b&gt; (&lt;i&gt;Business Logic Layer&lt;/i&gt;), &lt;b&gt;BFLL Layer&lt;/b&gt; (Busines Façade Logic Layer), &lt;b&gt;WCF Service Layer&lt;/b&gt; and several &lt;b&gt;Presentation layers&lt;/b&gt; depending of the pattern we use, like &lt;b&gt;MVC &lt;/b&gt;(Model-View-Controller), &lt;b&gt;MVP &lt;/b&gt;(Model-View-Presenter), etc.. Also, within the &lt;b&gt;N-Layer architecture&lt;/b&gt;, you can guess that &lt;b&gt;Entity Framework&lt;/b&gt; fits as the &lt;b&gt;DAL Layer&lt;/b&gt; (&lt;i&gt;Data Access Classes&lt;/i&gt;) as well as using EF entities as our disconnected entities to pass thru all the layers, all right? &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/cesardelatorre/WindowsLiveWriter/UpdatingdatausingEntityFrameworkinNTiera_9B49/image_4.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003.gif" width="582" height="428" /&gt;&lt;/a&gt; &lt;p&gt;BTW, not all N-Layer apps should be N-Tier apps, but all N-Tier Apps must internally be designed as N-Layer. I mean, there are many cases where the less you physically split your model, the better for performance (more tiers is good for scalability but not for pure performance, due to latencies). Remember, N-Layer is about logic layers. &lt;p&gt;OK!, so if we get back to the &lt;b&gt;N-Tier architecture&lt;/b&gt; (&lt;b&gt;physical tiers&lt;/b&gt;), like I said, we need remote mechanisms to communicate the client tier with the application server tier (for instance, WCF Services) and therefore when we query the database from the app server tier, to obtain data (like an Order), we keep it as an EF entity, then we disconnect it from the EF context (detach), WCF serializes it and sends that disconnected entity to the presentation tier (client apps &amp;amp; machines).  &lt;p&gt;So, most enterprise applications use an architectural pattern that needs a stateless facade for its business logic (like N-Tier &amp;amp; N-Layer apps). They have scenarios like WebServices or WCF, ASP.NET applications, Traditional Desktop Application (Windows Forms, WPF) consuming WCF Services, etc. in those cases data access works “disconnected oriented”, I mean, database data (in the real tables) are not blocked while the user is working in the client tier (btw, this is better for scalability). So, in the client/presentation tier, the user will be working and maybe, he changes that entity’s data (which is disconnected from the server) and after a while (at any time) the user submits that data to the application server and then the DAL layer (Entity Framework and LINQ to EF, in our case) will update that data into the database. Right?. Well, if we just do that, it will be just a &lt;b&gt;“Last-In-Wins”&lt;/b&gt; or what I call, a &lt;b&gt;“Too Optimistic Update”&lt;/b&gt; ;-) . Well, in many apps which are not very exigent or complex regarding updates, this can be enough, but then, we could have other apps where the users need to know if data (regarding the same entity and records he is using at client tier) has changed in the database while he was working and before he tried to update the data. In that case we should use “Optimistic Concurrency Updates” managing “Optimistic Concurrency Exceptions”. &lt;p&gt;So, I am using all the following stuff: &lt;p&gt;- &lt;b&gt;Entity Framework&lt;/b&gt; and &lt;b&gt;LINQ to Entities&lt;/b&gt; as our &lt;b&gt;DAL Layer&lt;/b&gt; &lt;p&gt;- &lt;b&gt;WCF&lt;/b&gt; as our remote communication technology &lt;p&gt;- Any .NET UI technology as our client App (WPF, WinForms, OBA or even Silverlight)  &lt;h6&gt;Simple way: Updating data in N-Tier applications and using Entity Framework with detached entities&lt;/h6&gt; &lt;p&gt;In order to understand what I mean, first of all, I am going to explain how to implement just simple updates in N-Tier applications and using Entity Framework. So this case is the one I called “Last-In-Wins” or a “Too Optimistic Update” ;-). So in this first case I won’t manage any Optimistic Concurrency Exception. &lt;p&gt;First of all, we’d have a business class (BLL class) which would be using EF &amp;amp; LINQ to Entities so that class would be querying the database; let’s say to get a Customer data and to return that entity’s data to the client/presentation tier (thru a WCF Service). The BLL class code could be something like the following code: &lt;p&gt;public class CustomerBll &lt;p&gt;{ &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private MyDataBaseEntities context; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public CustomerBll() &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context = new MyDataBaseEntities(); &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Customer GetCustomer(string customerID) &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var q = from c in context.Customers //.Include(&amp;quot;Orders&amp;quot;) &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; where c.CustomerID == numCustomerID &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; select c; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var customer = q.First(); &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.Detach(customer); &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return customer; &lt;p&gt;} &lt;p&gt;Ok, if you know LINQ to entities, this is a very simple method, right?. The important thing to take into account is the following: “&lt;b&gt;we are returning a disconnected/detached entity data object&lt;/b&gt;” passing it to the upper layers (Service layeràPresentation Layers). It means that regarding Entity Framework we’ll be working with &lt;i&gt;ObjectContext&lt;/i&gt; objects in a “&lt;b&gt;short lived context&lt;/b&gt;” way. &lt;u&gt;Basically, when we’ll close the loop, we’ll need to re-attach modified EntityObjects, that were updated outside of an ObjectContext (in detached state)&lt;/u&gt;. This is a very common scenario when we&amp;#39;re using stateless facades (most N-Tier &amp;amp; N-Layer apps). &lt;p&gt;Coming back to our code, then we could have a WCF Service serializing &amp;amp; returning the disconnected/detached entity. &lt;p&gt;Here you could see the Service contract for the method: &lt;p&gt;//WCF Contract &lt;p&gt;[OperationContract]  &lt;p&gt;Customer CustomerBll_GetCustomer(string customerID);  &lt;p&gt;... &lt;p&gt;... &lt;p&gt;//And now, the method’s implementation in the WCF class library:  &lt;p&gt;public Customer CustomerBll_GetCustomer(string customerID)  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new CustomerBll().GetCustomer(customerID);  &lt;p&gt;} &lt;p&gt;Ok, after that, the client app would be consuming the WCF Service and will display the entity’s data (customer’s data) let’s say in a WPF form. Remember that right now, the client app is working with a disconnected/detached entity object and there is not an ObjectStateManager tracking changes. We’ll see how it affects later on… &lt;p&gt;So, once the data is visible within a form, the user can start changing some data in that form until he decides to actually update that data into the application (for me, it means he wants to update that data into the database), pressing, for instance a big button which says “Update”. J &lt;br /&gt;Right, in this very moment the client application would be calling another WCF Service method called something like UpdateCustomer(), like you see down below: &lt;p&gt;public void CustomerBll_UpdateCustomer(Customer customer)  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; new CustomerBll().UpdateCustomer(customer);  &lt;p&gt;} &lt;p&gt;Then, that WCF method is calling the real business logic method, and this is where I am going to show you how to use Entity Framework to update the detached/disconnected but modified entity which is coming back from the client tier. This is the code (remember this is the simple case, I am not managing optimistic concurrency exceptions here): &lt;p&gt;public void UpdateCustomer(Customer customer)  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL) Entity must first be reunited with a Context  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //Note I do it with my custom extensor method for disconected environments (N-Tier, etc.)  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.&lt;b&gt;AttachUpdated(customer)&lt;/b&gt;; //Custom extensor method  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.&lt;b&gt;SaveChanges();&lt;/b&gt; &lt;p&gt;} &lt;p&gt;Ok, first, in order for the context to be able to update anything (the entity) into the database using SaveChanges(), it has first to have it attached to the context. So, context.SaveChanges() is an EF regular method we always gotta use to update data (changes). But if we’d just use the method context.Attach(customer) before that, it won’t work because that customer entity is new for the context (it was originally detached, serialized and sent to the client tier) and now the context does not know nothing about it, the context “thinks” it is a new entity object and it would not know any changes to update using the context.SaveChanges(). &lt;p&gt;The following is wrong code: &lt;p&gt;public void UpdateCustomer(Customer customer) //WRONG CODE  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL) Entity must first be reunited with a Context  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.&lt;b&gt;Attach (customer)&lt;/b&gt;; //Custom extensor method  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.&lt;b&gt;SaveChanges();&lt;/b&gt;//In this case, nothing happens here…  &lt;p&gt;} &lt;p&gt;So in this simpler case, when you’d call SaveChanges() nothing would happen. &lt;p&gt;That is why I created a custom EF extensor method called “context.AttachUpdated()”. To be able to attach updated entities which are disconnected and coming from the client Tier. &lt;p&gt;It is the following code: &lt;p&gt;public static void AttachUpdated(this ObjectContext context, EntityObject objectDetached)  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (objectDetached.EntityState == EntityState.Detached)  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; object currentEntityInDb = null;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (&lt;b&gt;context.TryGetObjectByKey&lt;/b&gt;(objectDetached.EntityKey, out currentEntityInDb))  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {  &lt;p&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.ApplyPropertyChanges&lt;/b&gt;(objectDetached.EntityKey.EntitySetName, objectDetached);  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL)Apply property changes to all referenced entities in context  &lt;p&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context.ApplyReferencePropertyChanges&lt;/b&gt;((IEntityWithRelationships)objectDetached,  &lt;p&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;&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; (IEntityWithRelationships)currentEntityInDb); //Custom extensor method  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {  &lt;p&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; throw new ObjectNotFoundException();  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;} &lt;p&gt;So, first of all we need to know what is new in this entity, I mean, what are the changes compared with the data we actually have in the database. In order to do that we’d need to query the database and get the actual data using the “context.TryGetObjectByKey()” method and attach it as the original data for that entity within the context. &lt;p&gt;Then, we can call the “context.ApplyPropertyChanges()” providing our new updated entity. What EF does is that it compares the original data (actual data in the database) with our new/updated entity and then it updates within the context all the property changes just regarding our specific entity (Customer, in this case). After that, when we call to “context.&lt;b&gt;SaveChanges()&lt;/b&gt;” in the main method, EF will detect what are actually those changes and it will be able to update it into the real database (SQL Server, for instance). &lt;p&gt;Notice that after calling to “context.ApplyPropertyChanges()” I am calling another method called “ApplyReferencePropertyChanges()”. This other method is actually another extensor method which applies all my entity property changes but into all the referenced entities within our EF model (Customer could be related to Company, Order, etc.). This is an important method, otherwise we’ll be taking into account just our isolated entity (Customer). Here you can see my “&lt;b&gt;context.ApplyReferencePropertyChanges()&lt;/b&gt;” custom context extensor method: &lt;p&gt;public static void ApplyReferencePropertyChanges(this ObjectContext context,  &lt;p&gt;IEntityWithRelationships newEntity,  &lt;p&gt;IEntityWithRelationships oldEntity)  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds())  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var oldRef = relatedEnd as EntityReference;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (oldRef != null)  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // this related end is a reference not a collection  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var newRef = newEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oldRef.EntityKey = newRef.EntityKey;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;  &lt;p&gt;} &lt;p&gt;So with that, we’re done!, it works ok following the method I said “Last In Wins” or a “Too Optimistic Update” ;-) &lt;p&gt;Btw, &lt;u&gt;another option&lt;/u&gt; (it works almost the same) would be not to query the database to know the actual data (kind of original data for the context) with “context.TryGetObjectByKey()” but to say to the context that &lt;i&gt;all the properties within my entity have actually changed&lt;/i&gt;, “&lt;i&gt;just because I say it&lt;/i&gt;”. After that, when we call “context.&lt;b&gt;SaveChanges()&lt;/b&gt;” it will update all the entity properties just because we said that!. J &lt;p&gt;Here you can see this other entity extensor method (In this case I coded as an entity extensor method instead as a context extensor method, ok?): &lt;p&gt;public static void SetAllModified&amp;lt;T&amp;gt;(this T entity, ObjectContext context) where T : IEntityWithKey  &lt;p&gt;{  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var stateEntry = context.ObjectStateManager.GetObjectStateEntry(entity.EntityKey);  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var propertyNameList = stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(pn =&amp;gt; pn.FieldType.Name);  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var propName in propertyNameList)  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; stateEntry.SetModifiedProperty(propName);  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }  &lt;p&gt;} &lt;p&gt;In this other case (using SetAllModified()) our code within &amp;quot;UpdateCustomer()&amp;quot; would be somethin like: &lt;p&gt;public void UpdateCustomer(Customer customer) &lt;br /&gt;{ &lt;br /&gt;&lt;strong&gt;context.Attach&lt;/strong&gt;(customer); &lt;br /&gt;&lt;strong&gt;customer.SetAllModified&lt;/strong&gt;(context);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // custom extension method &lt;br /&gt;&lt;strong&gt;context.SaveChanges&lt;/strong&gt;(); &lt;br /&gt;} &lt;p&gt;Cool!, this seems all great, we are happy and we are living in a wonderful world. Sure?. Well, it depends, but like I said at the beginning of this post, this code we have written does not cover scenarios where we want to manage “Optimistic Concurrency Updates &amp;amp; Exceptions”, I mean, let’s say any other guy changed some data, regarding that same data customer, during the timeframe after I performed my Customer query but before I actually updated it to the database. I mean, someone changed data in the database just before I called to &lt;strong&gt;context.AttachUpdated(customer)&lt;/strong&gt; and context.&lt;b&gt;SaveChanges(). &lt;/b&gt;Ok, then, the initial original user won’t be aware that he might be over writing that new data that the other second user updated… In many cases this can be dangerous depending on the application’s type. &lt;p&gt;Well, I guess this post is getting too long, I’ll write a second post (very soon) explaining &lt;em&gt;“How to: Update data in N-Tier applications and using &lt;b&gt;Entity Framework&lt;/b&gt; with detached entities and &lt;b&gt;managing Optimistic Concurrency Updates and Exceptions&lt;/b&gt;”.&lt;/em&gt; &lt;h4&gt;Optimistic Concurrency Updates using Entity Framework in N-Tier and N-Layer Applications (Part 2)&lt;/h4&gt; &lt;p&gt;This is my second post about &amp;quot;Updating data using Entity Framework in N-Tier and N-Layer Applications&amp;quot;. If you wanna read the basics, go to my first post here: &lt;p&gt;&lt;a href="http://blogs.msdn.com/cesardelatorre/archive/2008/09/04/updating-data-using-entity-framework-in-n-tier-and-n-layer-applications-short-lived-ef-contexts.aspx"&gt;http://blogs.msdn.com/cesardelatorre/archive/2008/09/04/updating-data-using-entity-framework-in-n-tier-and-n-layer-applications-short-lived-ef-contexts.aspx&lt;/a&gt; &lt;p&gt;So!, I finished my first post saying that the code I showed does not cover scenarios where we want to manage “&lt;strong&gt;Optimistic Concurrency Updates &amp;amp; Exceptions&lt;/strong&gt;”, I mean, let’s say any other guy changed some data, regarding that same data customer, during the timeframe after I performed my Customer query but before I actually updated it to the database. I mean, someone changed data in the database just before I called to &lt;strong&gt;context.AttachUpdated(customer)&lt;/strong&gt; and context.&lt;b&gt;SaveChanges(). &lt;/b&gt;Ok, then, the initial original user won’t be aware that he might be over writing that new data that the other second user updated… In many cases this can be dangerous depending on the application’s type. &lt;p&gt;The goal is: &lt;em&gt;“How to Update data in N-Tier and N-Layer applications using &lt;b&gt;Entity Framework&lt;/b&gt; with detached entities and &lt;b&gt;managing Optimistic Concurrency Updates and Exceptions&lt;/b&gt;”.&lt;/em&gt; &lt;p&gt;I think this is a great subject and the way you gotta do it is not very clear in official documentation neither in most of the Entity Framework books and articles (at least, at this time..). &lt;p&gt;Cool! :-) let’s see how we can achieve this new scenario!. &lt;p&gt;Fisrt of all, the Entity Framework can enforce optimistic concurrency when generating the update and delete SQL sentence. It does this by including original values in the WHERE clause for any entity property with the ConcurrencyMode attribute value set to &lt;strong&gt;Fixed&lt;/strong&gt;. &lt;u&gt;But by default, if you just create an EF model, entity fields are not set as concurrency fields&lt;/u&gt;. &lt;p&gt;Ok, so first thing would be to change that attribute to any entity field!. and which field do we use?, well, you can use whichever you like (Name, IDs, etc.) and you even can set several fields to have ConcurrencyMode attribute value set to &lt;strong&gt;Fixed&lt;/strong&gt;. &lt;p&gt;Here you can see how to change the EDM in VS.2008: &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/cesardelatorre/WindowsLiveWriter/OptimisticConcurrencyUpdatesusingEntityF_FA2/image_10.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image005.gif" width="610" height="367" /&gt;&lt;/a&gt; &lt;p&gt;If you change this &amp;quot;Customer&amp;quot; entity editing the EDM, you could see how the SQL sentence update is modified adding that column in the WHERE clause for any Update or Delete Commands:  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/cesardelatorre/WindowsLiveWriter/OptimisticConcurrencyUpdatesusingEntityF_FA2/image_6.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image007.gif" width="329" height="294" /&gt;&lt;/a&gt; &lt;p&gt;exec &lt;b&gt;sp_executesql N&amp;#39;update&lt;/b&gt; [SalesLT].[Customer] &lt;p&gt;&lt;b&gt;set [FirstName] = @0&lt;/b&gt; &lt;p&gt;&lt;b&gt;where (([CustomerID] = @1) and ([FirstName] = @2))&lt;/b&gt; &lt;p&gt;&amp;#39;,N&amp;#39;@0 nvarchar(17),@1 int,@2 nvarchar(14)&amp;#39;&lt;b&gt;,@0=N&amp;#39;Cesar App Changed&amp;#39;&lt;/b&gt;,@1=29485&lt;b&gt;,@2=N&amp;#39;Cesar Original Value&amp;#39;&lt;/b&gt; &lt;p&gt;In this case I&amp;#39;m using the &amp;quot;FirstName&amp;quot; field (even several fields), but, what I usually use is a TimeStamp field added to each table and entity. In that way I always can check in the same way (same field) if the record has changed. &lt;p&gt;Then, an OptimisticConcurrencyException is raised if the original row is not found.  &lt;p&gt;Here you can see that exception being raised when I modified the customer&amp;#39;s name in the database just before updating from the application using Entity Framework: &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/cesardelatorre/WindowsLiveWriter/OptimisticConcurrencyUpdatesusingEntityF_FA2/image_8.png"&gt;&lt;img border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image009.gif" width="397" height="239" /&gt;&lt;/a&gt; &lt;p&gt;&amp;quot;Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.&amp;quot; &lt;p&gt;Cool!, this is great, so when we get this exception we can decide if we want the user to know it, refresh de form and maybe start again, or we could show the differences, or we could even just catch the exception, log the problem&amp;nbsp; in a trace and just save the last operation. Ok!, &lt;strong&gt;&lt;u&gt;but think!, what is wrong when we are using detached entities?&lt;/u&gt;&lt;/strong&gt;. Sure! you got it!, the problem is that in order for the EF context to to know the original values, you&amp;#39;d need to use the same context since the very moment we started quering the database, updating, and so on. But, remember we are in a scenario (N-Tier and N-Layered apps) where EF contexts have a short life because we use stateless server objects and we detach the EF entity objects, and when we attach again the updated entity, we do it on a completely new context!, that new context knows nothing about the original query and the original values!! (if you wanna see more about this, just read my first post). &lt;p&gt;For instance, if we just set the concurrency mode to FIXED to any field and we use the code I showed in my first post about EF and data updates in N-Tier apps, it won&amp;#39;t work!. Why?, because when the business class is getting the updated data entity back, the context does not know the real original values, and if we use the first method I explained in my first post (using the &lt;strong&gt;AttachUpdated()&lt;/strong&gt; custom extensor method and the &lt;b&gt;context.TryGetObjectByKey&lt;/b&gt;()), the WHERE clause is going to compare it with current database values (which are not the real original values). Or if we use the second method I showed (using just the &lt;strong&gt;SetAllModified()&lt;/strong&gt;), it is even worse, in this case it does not even know anything about the current database values and it is going to place in the WHERE clause exactly the same value we want to update, so in this second case, it will always throw an exception!!!. &lt;p&gt;So, what do we need in order to make this to work?, of course, we&amp;#39;d need to &amp;quot;artificially&amp;quot; re-construct the context like if we had the same context!, I mean, we need to keep somewhere the original values we got the first time we queried the database, and attach it to the second short lived context, right before we attach the updated entity. In this case, it works like a charm!. :-) &lt;p&gt;Let&amp;#39;s see the code. Regarding the query business methods and WCF Service when we are just querying, we don&amp;#39;t need to change anything, we return data to the client tier in the same manner. But then, when we get the data in the client tier (let&amp;#39;s say in a WPF, Silverlight or WinForms app) we need to keep that data in a safe place. I mean, we need to clone the entity data so after the user has changed the data fields in the form and presses the Save button, we&amp;#39;ll actually send the updated data entity plus the original values, so the server components will be able to re-create a context who will know how to handle optimistic concurrency. &lt;p&gt;But, before getting deep into the server &amp;quot;update methods&amp;quot;, I wanna notice another problem. Entity Framework actually lacks of a &amp;quot;Clone()&amp;quot; entity method. First option (a really bad one) would be querying twice to the server WCF services so we get two data entities. But this approach is ugly because we loose performance and also there is a small possibility that while we query again, the data in the database has chaged. So, no way!, we need to clone our detached entity in the client side! &lt;p&gt;OK, for that, I&amp;#39;m using my own custom method (as a utility method in the client layers) which is based on memory streams copies: &lt;p&gt;//(CDLTLL) &lt;br /&gt;//Cloner by memory - Short code &lt;br /&gt;public static T CloneSerializing&amp;lt;T&amp;gt;(this T entityObject) where T : EntityObject, new() &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DataContractSerializer datContractSer = new DataContractSerializer(entityObject.GetType()); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MemoryStream memoryStream = new MemoryStream(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; datContractSer.WriteObject(memoryStream, entityObject); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; memoryStream.Position = 0; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; T clonedObject = (T)datContractSer.ReadObject(memoryStream); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return clonedObject;&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;br /&gt;} &lt;p&gt;You could find faster ways to clone EF detached entites, but the thing I like about this is that it is based just on a few lines of code. &lt;p&gt;For instance, Matthieu MEZIL has made an entity&amp;nbsp; cloner based on Reflection: &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/matthieu/archive/2008/05/31/entity-cloner.aspx"&gt;http://msmvps.com/blogs/matthieu/archive/2008/05/31/entity-cloner.aspx&lt;/a&gt; &lt;p&gt;Take a look. It could be faster (I have not compared it), but it is a lot of code..., well, you can choose. :-) &lt;p&gt;Then, we get to the fun stuff, let&amp;#39;s see how we handle the server code regarding updates and optimistic concurrency. &lt;p&gt;First of all, we need a slightly different WCF Service method, because we need to get two entities (original values and updated values): &lt;p&gt;public void CustomerBll_UpdateCustomerEx(Customer newCustomer, Customer originalCustomer) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; new CustomerBll().UpdateCustomerOptimisticConcurrency(newCustomer, originalCustomer); &lt;br /&gt;} &lt;p&gt;And then, our business class method, the &amp;quot;core&amp;quot; of this post!! :-) &lt;p&gt;public void UpdateCustomerOptimisticConcurrency(Customer detachedCustomer, Customer originalCustomer) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; try &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; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL) Original entity must first be reunited with a Context &lt;br /&gt;&lt;strong&gt;context.Attach(originalCustomer);&lt;/strong&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL)Apply property changes to all referenced entities in context&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;br /&gt;&lt;strong&gt;context.ApplyReferencePropertyChanges(detachedCustomer, originalCustomer);&lt;/strong&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Apply entity properties changes to the context &lt;br /&gt;&lt;strong&gt;context.ApplyPropertyChanges&lt;/strong&gt;(detachedCustomer.EntityKey.EntitySetName, //&amp;quot;Customers&amp;quot;, &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;&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; detachedCustomer); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL) EF SaveChanges() persists all updates to the store and &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // resets change tracking in the object context.&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;br /&gt;&lt;strong&gt;context.SaveChanges();&lt;/strong&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (&lt;strong&gt;OptimisticConcurrencyException e&lt;/strong&gt;) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //(CDLTLL) Concurrency Exception Management &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //context.Refresh(RefreshMode.ClientWins, newCustomer); // Last in wins &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //myLogger.Write(e); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //context.SaveChanges(); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //Manage or throw the exception &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw (e);  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;br /&gt;} &lt;p&gt;Here we first tell to the context what were the original values in the database when we first queried, then it is when we tell to the context about our updated data and we actually do it not just regarding our entity, we also apply changes to all referenced entities within our EF graph (using our custom extensor method called &lt;strong&gt;context.ApplyReferencePropertyChanges&lt;/strong&gt;) so when we finally call to &amp;quot;&lt;strong&gt;context.SaveChanges()&lt;/strong&gt;&amp;quot;, the &lt;strong&gt;EF will smoothly handle the &amp;quot;Optimistic Concurrency Updates and/or its Exception&amp;quot;!&lt;/strong&gt;, it will actually look for original values set in the WHERE clause of our Update/Delete final sentence. Cool!. :-) &lt;h6&gt;FINAL THOUGHTS&lt;/h6&gt; &lt;p&gt;It would be nice to have a way to actually hide the original values (hidden cloned entity) within the regular detached entity object. Doing so, it would be transparent for the developer who is working on the client layers... &lt;p&gt;You can also take a look to &lt;strong&gt;ENTITYBAG (by Danny Simmons)&lt;/strong&gt;. I&amp;#39;m not using it at all in the code I&amp;#39;ve been talking about. &lt;p&gt;&lt;em&gt;&lt;b&gt;&lt;u&gt;Perseus: Entity Framework EntityBag&lt;/u&gt;&lt;/b&gt;&lt;/em&gt; &lt;p&gt;&lt;a href="http://code.msdn.microsoft.com/entitybag/"&gt;http://code.msdn.microsoft.com/entitybag/&lt;/a&gt; &lt;p&gt;&lt;strong&gt;&lt;u&gt;EntityBag – Wrap-up and Future Directions&lt;/u&gt;&lt;/strong&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/dsimmons/archive/2008/01/28/entitybag-wrap-up-and-future-directions.aspx"&gt;http://blogs.msdn.com/dsimmons/archive/2008/01/28/entitybag-wrap-up-and-future-directions.aspx&lt;/a&gt; &lt;p&gt;&lt;strong&gt;&lt;u&gt;EntityBag Part II – Modes and Constructor&lt;/u&gt;&lt;/strong&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/dsimmons/archive/2008/01/20/entitybag-part-ii-modes-and-constructor.aspx"&gt;http://blogs.msdn.com/dsimmons/archive/2008/01/20/entitybag-part-ii-modes-and-constructor.aspx&lt;/a&gt; &lt;p&gt;&lt;em&gt;&lt;b&gt;EntityBag Modes with the Entity Framework (John Papa)&lt;/b&gt;&lt;/em&gt; &lt;p&gt;&lt;a href="http://nypapa.com/all/entitybag-modes-with-the-entity-framework/"&gt;http://nypapa.com/all/entitybag-modes-with-the-entity-framework/&lt;/a&gt; &lt;p&gt;&lt;em&gt;&lt;b&gt;Coming to the Entity Framework: A Serializable EntityBag for n-Tier Deployment &lt;/b&gt;&lt;/em&gt; &lt;p&gt;&lt;a href="http://oakleafblog.blogspot.com/2008/01/coming-to-entity-framework-serializable.html"&gt;http://oakleafblog.blogspot.com/2008/01/coming-to-entity-framework-serializable.html&lt;/a&gt; &lt;p&gt;The &lt;strong&gt;EntityBag&lt;/strong&gt; concept is actually quite neat and it solves many points I talked about, but it has also several restrictions: &lt;p&gt;First of all, there’s the fact that it requires us to run .Net and the EF on the client, and it also requires that the code for your object model has to be available on the client, so, you loose the great discover and interoperability we have with basic Web Services (or advanced WCF wsHttp or basicHttp services, etc.), so I guess ENTITYBAG is not interoperable with Java or any non .NET language. &lt;p&gt;Examples &lt;hr align="center" /&gt;  &lt;p&gt;The example in this topic is based on the &lt;a href="http://msdn.microsoft.com/en-us/library/bb387147.aspx"&gt;Adventure Works Sales Model&lt;/a&gt;. In this example, an updated SalesOrderDetail object is passed to the UpdateItemChanges method, together with the original object. This enables changes to be applied without querying for the object or having to persist it in memory. &lt;pre&gt;private static void ApplyItemUpdates(SalesOrderDetail originalItem,&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SalesOrderDetail updatedItem)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (AdventureWorksEntities advWorksContext = &lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new AdventureWorksEntities())&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Attach the original item to the object context.&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; advWorksContext.Attach(originalItem);&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Call the ApplyPropertyChanges method to apply changes&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // from the updated item to the original version.&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; advWorksContext.ApplyPropertyChanges(&amp;quot;SalesOrderDetail&amp;quot;,&lt;/pre&gt;&lt;pre&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; updatedItem);&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; advWorksContext.SaveChanges();&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;catch (InvalidOperationException ex)&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(ex.ToString());&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;In this example, the original SalesOrderDetail object is retrieved and then changes are applied to it based on an updated SalesOrderDetail object that is passed to the UpdateItemChanges method. &lt;pre&gt;private static void ApplyItemUpdates(SalesOrderDetail updatedItem)&lt;/pre&gt;&lt;pre&gt;{&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Define an ObjectStateEntry and EntityKey for the current object.&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; EntityKey key;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; object originalItem;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (AdventureWorksEntities advWorksContext =&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new AdventureWorksEntities())&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Create the detached object&amp;#39;s entity key.&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key = advWorksContext.CreateEntityKey(&amp;quot;SalesOrderDetail&amp;quot;, updatedItem);&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Get the original item based on the entity key from the context&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // or from the database.&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (advWorksContext.TryGetObjectByKey(key, out originalItem))&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&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; // Call the ApplyPropertyChanges method to apply changes&lt;/pre&gt;&lt;pre&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; // from the updated item to the original version.&lt;/pre&gt;&lt;pre&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; advWorksContext.ApplyPropertyChanges(&lt;/pre&gt;&lt;pre&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; key.EntitySetName, updatedItem);&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; advWorksContext.SaveChanges();&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (InvalidOperationException ex)&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(ex.ToString());&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre&gt;}&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s one approach to updating a reference in an entity in the mid tier of a SOA app. 
&lt;p&gt;public static EnduranceActivity UpdateEnduranceActivity(EnduranceActivity currentActivity, EnduranceActivity originalActivity, Route newRoute)
&lt;p&gt;{
&lt;p&gt;&amp;nbsp;&amp;nbsp; using (FitnessAppContainer appContainer = new FitnessAppContainer(ConnectionString))
&lt;p&gt;&amp;nbsp;&amp;nbsp; {
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (null != newRoute)
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalActivity.Route = newRoute;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; appContainer.Attach(originalActivity);
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; appContainer.ApplyPropertyChanges(&amp;quot;FitnessAppContainer.EnduranceActivitySet&amp;quot;, currentActivity);
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; appContainer.SaveChanges();
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return originalActivity;
&lt;p&gt;}
&lt;p&gt;We are looking at adding an option to ApplyPropertyChanges that will update references as well for V2 as well as other features that will make this easier.
&lt;p&gt;· Here&amp;#39;s a more generic approach based on a &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3304889&amp;amp;SiteID=1"&gt;related post&lt;/a&gt;&amp;nbsp;by Danny Simmons. I have confirmed that&amp;nbsp;this works: 
&lt;p&gt;Code Snippet
&lt;p&gt;public static EnduranceActivity UpdateEnduranceActivity(EnduranceActivity currentActivity, EnduranceActivity originalActivity, Route newRoute)
&lt;p&gt;{
&lt;p&gt;&amp;nbsp;&amp;nbsp; using (FitnessAppContainer appContainer = new FitnessAppContainer(ConnectionString))
&lt;p&gt;&amp;nbsp;&amp;nbsp; {
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; appContainer.Attach(originalActivity);
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ApplyReferencePropertyChanges(
&lt;p&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; (IEntityWithRelationships)currentActivity, 
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (IEntityWithRelationships)originalActivity);
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; appContainer.ApplyPropertyChanges(
&lt;p&gt;&amp;quot;FitnessAppContainer.EnduranceActivitySet&amp;quot;, 
&lt;p&gt;currentActivity);
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; appContainer.SaveChanges();
&lt;p&gt;&amp;nbsp;&amp;nbsp; }
&lt;p&gt;&amp;nbsp;&amp;nbsp; return originalActivity;
&lt;p&gt;}
&lt;p&gt;public static void ApplyReferencePropertyChanges(
&lt;p&gt;IEntityWithRelationships oldEntity, 
&lt;p&gt;IEntityWithRelationships newEntity)
&lt;p&gt;{
&lt;p&gt;foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds())
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;p&gt;&amp;nbsp;&amp;nbsp; var oldRef = relatedEnd as EntityReference;
&lt;p&gt;&amp;nbsp;&amp;nbsp; if (oldRef != null)
&lt;p&gt;&amp;nbsp;&amp;nbsp; {
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// this related end is a reference not a collection
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var newRef = newEntity.RelationshipManager
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName)
&lt;p&gt;as EntityReference;
&lt;p&gt;oldRef.EntityKey = newRef.EntityKey;
&lt;p&gt;&amp;nbsp;&amp;nbsp; }
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;· Hi, 
&lt;p&gt;I have used this method as part of a generic graph update method for my wcf services. However, it appears to ignore the reference values entirely. I can see that the reference properties are set in the method&amp;nbsp;but when savechanges is called they do not persist? 
&lt;p&gt;When i test out workign with an always connected object graph (no wcf) the method works fine and the changes persist, any ideas?
&lt;p&gt;On a side note, i&amp;#39;ve resorted to using dependency injection to have specific classes responsible for managing the updating of objects from wcf services as reflection was getting way too messy. I have the concept of allowing an udpate strategy key to be passed into the web service to instruct how the graph should be updated, with sensible defaults of course (association depth of 1 for example).
&lt;p&gt;public void Update&amp;lt;T&amp;gt;(T entity, string updateStrategyKey)
&lt;p&gt;{
&lt;p&gt;EntityObject updatedEntity = entity as EntityObject;
&lt;p&gt;// we&amp;#39;re only interested in detached entities, any others will be updated by SaveChanges anyway
&lt;p&gt;if (updatedEntity == null || updatedEntity.EntityState != EntityState.Detached)
&lt;p&gt;return;
&lt;p&gt;// get the current (old) entity from the object state manager using the updated entity
&lt;p&gt;EntityObject oldEntity = GetObjectByKey(updatedEntity) as EntityObject;
&lt;p&gt;// get context and relationship info about old and updated
&lt;p&gt;ObjectContext objectContext = this.ObjectContext;
&lt;p&gt;Type updatedEntityType = updatedEntity.GetType();
&lt;p&gt;Type updatedEntityBaseType = GetBaseType(updatedEntityType);
&lt;p&gt;// apply reference property changes (not handled by context&amp;#39;s ApplyPropertyChanges)
&lt;p&gt;&lt;b&gt;ApplyReferencePropertyChanges(oldEntity, updatedEntity);&lt;/b&gt;
&lt;p&gt;// apply scalar property changes
&lt;p&gt;&lt;b&gt;objectContext.ApplyPropertyChanges(updatedEntityBaseType.Name.ToString(), updatedEntity);&lt;/b&gt;
&lt;p&gt;// if an update strategy is in place, use a dependency injected service to implement if available
&lt;p&gt;if (!String.IsNullOrEmpty(updateStrategyKey) &amp;amp;&amp;amp; updateStrategyKey != UpdateStrategyKey.RootOnly.ToString())
&lt;p&gt;{
&lt;p&gt;string repositoryGraphUpdaterServiceID = updatedEntityType.ToString() + &amp;quot;GraphUpdater&amp;quot;;
&lt;p&gt;IRepositoryGraphUpdater repositoryGraphUpdater = ServiceLocator.TryResolve&amp;lt;IRepositoryGraphUpdater&amp;gt;(repositoryGraphUpdaterServiceID);
&lt;p&gt;if (repositoryGraphUpdater != null)
&lt;p&gt;{
&lt;p&gt;repositoryGraphUpdater.Update(updatedEntity, updateStrategyKey);
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;&lt;b&gt;// apply reference property changes (not handled by context&amp;#39;s ApplyPropertyChanges)&lt;/b&gt;
&lt;p&gt;&lt;b&gt;private&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;void&lt;/b&gt;&lt;b&gt; ApplyReferencePropertyChanges(&lt;/b&gt;&lt;b&gt;IEntityWithRelationships&lt;/b&gt;&lt;b&gt; oldEntity, &lt;/b&gt;&lt;b&gt;IEntityWithRelationships&lt;/b&gt;&lt;b&gt; updatedEntity)&lt;/b&gt;
&lt;p&gt;&lt;b&gt;{&lt;/b&gt;
&lt;p&gt;&lt;b&gt;foreach&lt;/b&gt;&lt;b&gt; (&lt;/b&gt;&lt;b&gt;var&lt;/b&gt;&lt;b&gt; relatedEnd &lt;/b&gt;&lt;b&gt;in&lt;/b&gt;&lt;b&gt; oldEntity.RelationshipManager.GetAllRelatedEnds())&lt;/b&gt;
&lt;p&gt;&lt;b&gt;{&lt;/b&gt;
&lt;p&gt;&lt;b&gt;var&lt;/b&gt;&lt;b&gt; oldRef = relatedEnd &lt;/b&gt;&lt;b&gt;as&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;EntityReference&lt;/b&gt;&lt;b&gt;;&lt;/b&gt;
&lt;p&gt;&lt;b&gt;if&lt;/b&gt;&lt;b&gt; (oldRef != &lt;/b&gt;&lt;b&gt;null&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;
&lt;p&gt;&lt;b&gt;{&lt;/b&gt;
&lt;p&gt;&lt;b&gt;// this related end is a reference not a collection&lt;/b&gt;
&lt;p&gt;&lt;b&gt;var&lt;/b&gt;&lt;b&gt; newRef = updatedEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName)&lt;/b&gt;
&lt;p&gt;&lt;b&gt;as&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;b&gt;EntityReference&lt;/b&gt;&lt;b&gt;;&lt;/b&gt;
&lt;p&gt;&lt;b&gt;oldRef.EntityKey = newRef.EntityKey;&lt;/b&gt;
&lt;p&gt;&lt;b&gt;}&lt;/b&gt;
&lt;p&gt;&lt;b&gt;}&lt;/b&gt;
&lt;p&gt;&lt;b&gt;}&lt;/b&gt;
&lt;p&gt;· I&amp;#39;ve just been debugging this and it&amp;#39;s the line in red below that doesn&amp;#39;t appear to work. What happens for me is that the attached and detached entity keys appear from the old entity (attached) and the updated entity (yet to be attached) is ignored. 
&lt;p&gt;This is causing&amp;nbsp;major&amp;nbsp;problems for us as we can not seem to update any entity&amp;nbsp;references as a result (as&amp;nbsp;attach and attachto are not viaable options when protecting updates). 
&lt;p&gt;Let&amp;#39;s say we have oldEntity below passed in&amp;nbsp;as a customer with a null party reference as follows Customer.Party. The updatedEntity is a detached Customer with an updated party reference. 
&lt;p&gt;The problem then seems to be that we cannot use a detached updatedEntity when the oldEntity is attached and the reference you want to update on the attached entity is null, is this correct?
&lt;p&gt;// apply reference property changes (not handled by context&amp;#39;s ApplyPropertyChanges) oldentiy is attached and updatedentity not
&lt;p&gt;private void ApplyReferencePropertyChanges(IEntityWithRelationships oldEntity, IEntityWithRelationships updatedEntity)
&lt;p&gt;{
&lt;p&gt;foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds())
&lt;p&gt;{
&lt;p&gt;var oldRef = relatedEnd as EntityReference;
&lt;p&gt;if (oldRef != null)
&lt;p&gt;{
&lt;p&gt;// this related end is a reference not a collection
&lt;p&gt;&lt;b&gt;var newRef = updatedEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName)&lt;/b&gt;
&lt;p&gt;&lt;b&gt;as EntityReference;&lt;/b&gt;
&lt;p&gt;oldRef.EntityKey = newRef.EntityKey;
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;}
&lt;p&gt;· aha!
&lt;p&gt;I&amp;#39;ve just discovered that one must set the REFERENCE value on the client for many to ones. I assumed (wrongly) that you could set the property itself and that EF would set the reference on the way back!
&lt;p&gt;It&amp;#39;s not very intuitive however to have the following code, any ideas why this gets generated and not just PartyReference like on the entity class itself?
&lt;p&gt;// update the customer&amp;#39;s party
&lt;p&gt;Party party = client.GetParty(7);
&lt;p&gt;EntityReferenceOfPartyXwpgZWOi partyRef = new EntityReferenceOfPartyXwpgZWOi();
&lt;p&gt;partyRef.EntityKey = party.EntityKey;
&lt;p&gt;customer.PartyReference = partyRef;
&lt;p&gt;I&amp;#39;ve finally gotten this working after days of struggle.
&lt;p&gt;I&amp;#39;ve got a simple database of People and Departments:
&lt;p&gt;&lt;img border="0" alt="ADO.NET Entity Framework Entity Data Model diagram with Department and Person objects" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image010.gif" width="385" height="162" /&gt;
&lt;p&gt;I can use strongly-typed ASP.NET MVC views for reference/navigation properties! See the list of departments...
&lt;p&gt;&lt;img border="0" alt="ASP.NET MVC with DropDownList" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image011.gif" width="487" height="453" /&gt;
&lt;p&gt;Part of my Person/Edit view:
&lt;p&gt;&amp;lt;% using (Html.BeginForm()) {%&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;%= Html.Hidden(&amp;quot;Id&amp;quot;, Model.Id) %&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;fieldset&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;legend&amp;gt;Fields&amp;lt;/legend&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;label for=&amp;quot;Name&amp;quot;&amp;gt;Name:&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;%= Html.TextBox(&amp;quot;Name&amp;quot;, Model.Name) %&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;label for=&amp;quot;DepartmentId&amp;quot;&amp;gt;Department:&amp;lt;/label&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;%= Html.DropDownList(&amp;quot;DepartmentId&amp;quot;, new SelectList((IEnumerable)ViewData[&amp;quot;Departments&amp;quot;], &amp;quot;Id&amp;quot;, &amp;quot;Name&amp;quot;))%&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;p&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Save&amp;quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/p&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/fieldset&amp;gt;&lt;br /&gt;&amp;lt;% } %&amp;gt;
&lt;p&gt;Part of my Person controller:
&lt;p&gt;//&lt;br /&gt;// GET: /Person/Edit/5&lt;br /&gt;public ActionResult Edit(Guid id)&lt;br /&gt;{&lt;br /&gt;ViewData[&amp;quot;Departments&amp;quot;] = ctx.Department;&lt;br /&gt;Person model = (from Person p in ctx.Person&lt;br /&gt;where p.Id == id&lt;br /&gt;select p).FirstOrDefault();&lt;br /&gt;return View(model);&lt;br /&gt;}&lt;br /&gt;//&lt;br /&gt;// POST: /Person/Edit&lt;br /&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ActionResult Edit(Person model)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; ctx.AttachUpdated(model); &amp;nbsp;//extension&lt;br /&gt;&amp;nbsp; &amp;nbsp; ctx.SaveChanges();&lt;br /&gt;return RedirectToAction(&amp;quot;Index&amp;quot;);&lt;br /&gt;}
&lt;p&gt;To get this working, I extended the Person EntityObject with a new DepartmentId property.
&lt;p&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.Objects.DataClasses;&lt;br /&gt;namespace ProjectName.Models&lt;br /&gt;{&lt;br /&gt;public partial class Person : EntityObject&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;public Guid DepartmentId&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;get&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;try&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;return (Guid)this.DepartmentReference.EntityKey.EntityKeyValues[0].Value;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;catch&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;return Guid.Empty;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &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; }&lt;br /&gt;set&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;this.DepartmentReference.EntityKey = new EntityKey(&amp;quot;JunkEntities.Department&amp;quot;, &amp;quot;Id&amp;quot;, value);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}
&lt;p&gt;And I extended the Entity Framework ObjectContext with new AttachUpdated and ApplyReferencePropertyChanges methods:
&lt;p&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.Objects;&lt;br /&gt;using System.Data.Objects.DataClasses;&lt;br /&gt;public static class EntityFrameworkExtensionMethods&lt;br /&gt;{&lt;br /&gt;public static void AttachUpdated(this ObjectContext ctx, EntityObject objectDetached)&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;if (objectDetached.EntityKey == null)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;String entitySetName = ctx.DefaultContainerName + &amp;quot;.&amp;quot; + objectDetached.GetType().Name;&lt;br /&gt;Guid objectId = (Guid)objectDetached.GetType().GetProperty(&amp;quot;Id&amp;quot;).GetValue(objectDetached, null);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; objectDetached.EntityKey = new System.Data.EntityKey(entitySetName, &amp;quot;Id&amp;quot;, objectId);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;if (objectDetached.EntityState == EntityState.Detached)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;object currentEntityInDb = null;&lt;br /&gt;if (ctx.TryGetObjectByKey(objectDetached.EntityKey, out currentEntityInDb))&lt;br /&gt;&amp;nbsp; &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; ctx.ApplyPropertyChanges(objectDetached.EntityKey.EntitySetName, objectDetached);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ctx.ApplyReferencePropertyChanges((IEntityWithRelationships)objectDetached,&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; (IEntityWithRelationships)currentEntityInDb); &amp;nbsp;//extension&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;else&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;throw new ObjectNotFoundException();&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;public static void ApplyReferencePropertyChanges(this ObjectContext ctx, IEntityWithRelationships newEntity, IEntityWithRelationships oldEntity)&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds())&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;var oldRef = relatedEnd as EntityReference;&lt;br /&gt;if (oldRef != null)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;br /&gt;var newRef = newEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; oldRef.EntityKey = newRef.EntityKey;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}
&lt;p&gt;I just wanted to document my progress here. Please suggest improvements.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=192" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author><category term="Entity Framework" scheme="http://community.icburner.com/blogs/webdev/archive/tags/Entity+Framework/default.aspx" /><category term="POCO" scheme="http://community.icburner.com/blogs/webdev/archive/tags/POCO/default.aspx" /></entry><entry><title>使用 LINQ To SQL 和Entity Framework实现灵活的数据访问</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/31/linq-to-sql-entity-framework.aspx" /><id>/blogs/webdev/archive/2009/05/31/linq-to-sql-entity-framework.aspx</id><published>2009-05-30T17:12:40Z</published><updated>2009-05-30T17:12:40Z</updated><content type="html">&lt;p&gt;Microsoft 已面向开发人员发布了两种旨在减少关系数据领域和面向对象的编程之间的阻抗失谐的产品：LINQ to SQL 和 ADO.NET Entity Framework。借助其中任何一种产品，您不必编写大部分探测代码，即可实现对象持久性。 &lt;p&gt;　　本文使用以下技术： &lt;p&gt;LINQ to SQL、ADO.NET Entity Framework和 SOA &lt;p&gt;　　迄今为止，Microsoft 已面向开发人员发布了两种旨在减少关系数据领域和面向对象的编程之间的阻抗失谐的产品：LINQ to SQL 和 ADO.NET Entity Framework。借助其中任何一种产品，您不必编写大部分探测代码，即可实现对象持久性。但是，将这些对象关系映射 (ORM) 技术应用到面向服务的应用程序体系结构为应用程序开发人员带来了全新的挑战。 &lt;p&gt;　　例如，如何创建将对象持久性与应用程序其他部分分离的数据访问层 (DAL)，以便在需要时使用一个 ORM 提供程序换出另一个提供程序。如何在客户端没有安装 LINQ to SQL 或Entity Framework的情况下跟踪对实体的更改？如何通过仅调用服务一次即可在单个事务中插入、更新和删除多个实体？ &lt;p&gt;在本文中，我将进行简要介绍并提供一些有关如何解决上述问题的建议。首先，我将基于 Northwind 示例数据库创建一个用于处理订单的 DAL。DAL 的两种实现（一种使用 LINQ to SQL，一种使用Entity Framework）依赖于一个接口（请参见图 1）。LINQ to SQL 和Entity Framework都具有基于数据库架构生成实体的工具，但是 DAL 并不使用这些实体，而是仅公开通常忽略涉及到持久性的数据传输对象 (DTO)。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image002.jpg" width="608" height="369" /&gt; &lt;p&gt;　图 1 适用于订单处理应用程序的面向服务的体系结构 &lt;p&gt;LINQ to SQL 和Entity Framework使用不同的方法持久化断开连接的实体，具体取决于要创建新实体还是更新现有的实体。因此，为了调用合适的 API，您必须事先了解实体的状态。例如，如果您具有 UpdateOrder 方法接受带有订单明细的订单，可以为 UpdateOrder 方法添加三个参数，以接受创建、更新和删除的订单明细。但这很容易因探测订单明细而使方法签名变得混乱。 &lt;p&gt;　　此外，您可以带外传递更改状态信息（例如在 SOAP 或 HTTP 标头中传递），但这样做会使更改跟踪与通信协议相结合。下面我将介绍另一种方法 — 将更改状态作为每个实体的数据约定的一部分，我建议使用这种方法： &lt;p&gt;[DataContract]&lt;br /&gt;public enum TrackingInfo&lt;br /&gt;{&lt;br /&gt;[EnumMember]&lt;br /&gt;Unchanged,&lt;br /&gt;[EnumMember]&lt;br /&gt;Created,&lt;br /&gt;[EnumMember]&lt;br /&gt;Updated,&lt;br /&gt;[EnumMember]&lt;br /&gt;Deleted&lt;br /&gt;} &lt;p&gt;除了其他属性之外，每个 DTO 都有一个使用 TrackingInfo 枚举的 TrackingState 属性。双方只需同意此数据约定即可。 &lt;p&gt;　　虽然我为每个 DTO 添加了 TrackingState 属性，但我还必须依赖没有安装 LINQ to SQL 或Entity Framework的客户端来跟踪创建、更新或删除的对象，以及将 TrackingState 属性设置为相应的值（请参见图 1）。我创建了一个通用更改跟踪集合来执行此任务。此集合有两种类型：一种扩展 ObservableCollection&amp;lt;T&amp;gt; 以用于 Windows Presentation Foundation (WPF) 应用程序；一种扩展 BindingList&amp;lt;T&amp;gt; 以用于 Windows 窗体应用程序。每种集合都可在从集合中删除项目之前缓存删除的项目，并且每种集合都具有 GetChanges 方法，该方法只返回插入、更新或删除的项目。 &lt;p&gt;创建数据访问层 &lt;p&gt;DAL 有助于将应用程序的其他部分与对象持久性的详细信息隔离开。为此，通过 DAL 公开的对象必须排除任何特定数据访问技术的其余部分。LINQ to SQL 和Entity Framework允许您使用命令行工具和 Visual Studio 设计器创建实体，但是这些代码生成的实体中的一些项目与它们的源相悖。 &lt;p&gt;　　例如，为了支持关联对象的延迟加载，LINQ to SQL 使用 EntityRef&amp;lt;T&amp;gt; 和 EntitySet&amp;lt;T&amp;gt; 集合类型表示数据关系，而Entity Framework使用 EntityReference&amp;lt;T&amp;gt; 和 EntityCollection&amp;lt;T&amp;gt; 表示导航属性。此外，这些实体添加了旨在支持客户端服务器方案（例如使用局部方法的验证和使用 INotifyPropertyChanged 的数据绑定）的代码元素，如果这些实体只用于与 Windows Communication Foundation (WCF) 服务进行通信，则无需使用这些代码元素。 &lt;p&gt;　　由于 LINQ to SQL 和Entity Framework支持使用 DataContractSerializer 对实体进行序列化（使用 DataContract 和 DataMember 属性进行标记），因此您可能希望将它们用于您的服务操作中，而无论这样做会带来多大的负担。毕竟，当您设置 WCF 服务引用时，集合类型（如 LINQ to SQL 和Entity Framework使用的集合类型）在客户端上显示为简单数组。 &lt;p&gt;　　但是，如果您将 LINQ to SQL DataContext 的 SerializationMode 从“None”设置为“Unidirectional”，则只有一对多关系中的“多”方标有 DataMember 属性。这表示如果您的 Order 实体有 Customer 和 Order_Details 两个属性，只有 Order_Details 标有 DataMember 并包含在数据约定中，而 Customer 则不能如此。另一方面，Entity Framework包含的字段可能比您希望包含在数据约定中的要多，从而在客户端上生成用以实现特定于Entity Framework的功能的类，例如，EntityKey、EntityKeyMember、EntityObject 或 EntityReference。 &lt;p&gt;鉴于上述原因，您应该避免通过 DAL 公开 LINQ to SQL 或Entity Framework工具生成的实体，改为返回简单的 DTO，它们存在的目的只是跨服务边界传送数据。例如，Order DTO（请参见图 2）只包含属性，不包括方法。所有的 DTO 均在 DataTransferObjects 命名空间中定义，以与工具生成的同名类进行区分。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003.gif" width="1" height="1" /&gt;图 2 表示 Northwind 中的订单的 DTO  &lt;p&gt;namespace DataTransferObjects&lt;br /&gt;{&lt;br /&gt;[DataContract]&lt;br /&gt;public class Order&lt;br /&gt;{&lt;br /&gt;[DataMember]&lt;br /&gt;public int OrderID { get; set; }&lt;br /&gt;[DataMember]&lt;br /&gt;public string CustomerID { get; set; }&lt;br /&gt;[DataMember]&lt;br /&gt;public string CustomerName { get; set; }&lt;br /&gt;[DataMember]&lt;br /&gt;public DateTime? OrderDate { get; set; }&lt;br /&gt;[DataMember]&lt;br /&gt;public List&amp;lt;OrderDetail&amp;gt; OrderDetails { get; set; }&lt;br /&gt;[DataMember]&lt;br /&gt;public byte[] Updated { get; set; }&lt;br /&gt;[DataMember]&lt;br /&gt;public TrackingInfo TrackingState { get; set; }&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;　　灵活的 DAL 应该可以使 Order Service 不受基础持久性技术更改的影响。例如，假设您选择使用 SQL Server 来存储数据并且您的对象模型和数据库架构极其类似，因此，您决定使用 LINQ to SQL 持久化对象。但是，当您编写 LINQ to SQL 持久性逻辑后不久，您决定使用其他数据库系统（如 Oracle）或希望使用Entity Framework的映射功能来分离概念架构和逻辑架构。或许一种新的数据访问技术已推出，您希望使用该技术。如果您设计了基于插件体系结构的灵活 DAL，则应该可以根据 app.config 中的条目随时切换提供程序。 &lt;p&gt;　　为实现此灵活性，我创建了 IDataProvider 接口，该接口具有用以检索和更新客户订单，以及检索支持的客户和产品信息的方法（请参见图 3）。本示例应用程序包括两个实现 IDataProvider 的类：使用 LINQ to SQL 的 SqlDataProvider；使用Entity Framework和 LINQ to Entities 的 EntityDataProvider（请参见图 1）。您仅可以为 DAL 的 app.config 文件中的“DataProvider”设置输入完全限定的类名称，并使用 Assembly 类的 CreateInstance 方法创建此类的实例，从而将其转换为 IDataProvider。Order Service 对实现 IDataProvider 而使用的类没有特别要求，因此您可以选择任何数据提供程序： &lt;p&gt;IDataProvider provider =&lt;br /&gt;Assembly.GetExecutingAssembly()&lt;br /&gt;.CreateInstance(Settings.Default.DataProvider, true)&lt;br /&gt;as IDataProvider; &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_1.gif" width="1" height="1" /&gt;图 3 将 DAL 与接口分离 &lt;p&gt;namespace DataAccessLayer&lt;br /&gt;{&lt;br /&gt;// Alias the namespace containing Data Transfer Objects&lt;br /&gt;using DTO = DataTransferObjects;&lt;br /&gt;public interface IDataProvider&lt;br /&gt;{&lt;br /&gt;// Retrieve Customers, Products, Orders&lt;br /&gt;DTO.Customer[] GetCustomers();&lt;br /&gt;DTO.Product[] GetProducts();&lt;br /&gt;DTO.Order[] GetCustomerOrders(string customerID);&lt;br /&gt;// CRUD operations for Order&lt;br /&gt;DTO.Order GetOrder(int orderID);&lt;br /&gt;DTO.Order CreateOrder(DTO.Order order);&lt;br /&gt;DTO.Order UpdateOrder(DTO.Order order);&lt;br /&gt;void DeleteOrder(DTO.Order order);&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;　　默认情况下，LINQ to SQL 和Entity Framework会在与项目相同的命名空间中生成实体。但是，如果将新的“LINQ to SQL Classes”项目置于 L2S 项目文件夹中，此工具会使用此文件夹名作为嵌套的命名空间，这有助于区分 LINQ to SQL 实体和 DTO 实体。同样，如果将新的“ADO.NET Entity Data Model”置于 L2E 项目文件夹中，Entity Framework实体也会存在于嵌套的 L2E 命名空间。另外，您可以在 LINQ to SQL 的属性窗口和Entity Framework可视组件设计器中指定命名空间。 &lt;p&gt;　　此处，我选择为 LINQ to SQL 和Entity Framework两者生成实体，并将查询结果转换为 DTO。此时还存在以下两种可能性：完全消除工具生成的实体；使用 XML 文件映射 DTO。Entity Framework 已使用了 XML 映射文件，但是在Entity Framework的第一个版本中，使用简单的 C# 对象 (POCO) 根本无法实现完全的持久化透明 (PI)。在版本 1 中，您可以实现此目标，但实体必须首先实现两个接口：IEntityWithRelationships 和 IEntityWithChangeTracking，因此这种情况需要使用 IPOCO（POCO + 接口）。.希望Entity Framework的将来版本能够改进对 POCO 和持久化透明的支持。 &lt;p&gt;LINQ to SQL 确实能够很好地支持使用 XML 映射文件将 POCO 映射到数据库架构。但是，从 L2S.Order 或 L2E.Order 投影到 DTO.Order 提供了更大程度的灵活性。例如，图 4 显示的 SqlDataProvider 的 GetOrder 方法，此方法根据 L2S.Order Customer 属性的 ContactName 属性填充 DTO.Order 的 CustomerName 属性，实际上恰恰反映了 Customer 和 Order 之间的关系。同理，我也可以根据 L2S.Order_Detail 的 Product 属性设置 DTO.OrderDetail 的 ProductName 属性。在每一种情况下，我都必须将 DataContext 的 LoadOptions 属性配置为预先加载 LINQ to SQL 实体。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_2.gif" width="1" height="1" /&gt;图 4 GetOrder 方法使用 LINQ to SQL 框架返回 DTO.Order  &lt;p&gt;namespace DataAccessLayer&lt;br /&gt;{&lt;br /&gt;using DataAccessLayer.L2S;&lt;br /&gt;using DTO = DataTransferObjects;&lt;br /&gt;public class SqlDataProvider : IDataProvider&lt;br /&gt;{&lt;br /&gt;public DTO.Order GetOrder(int orderID)&lt;br /&gt;{&lt;br /&gt;using (NorthwindDataContext db = new NorthwindDataContext&lt;br /&gt;(Settings.Default.NorthwindSqlConnection))&lt;br /&gt;{&lt;br /&gt;// Set load options&lt;br /&gt;DataLoadOptions opts = new DataLoadOptions();&lt;br /&gt;opts.LoadWith&amp;lt;Order&amp;gt;(o =&amp;gt; o.Customer);&lt;br /&gt;opts.LoadWith&amp;lt;Order&amp;gt;(o =&amp;gt; o.Order_Details);&lt;br /&gt;opts.LoadWith&amp;lt;Order_Detail&amp;gt;(od =&amp;gt; od.Product);&lt;br /&gt;db.LoadOptions = opts;&lt;br /&gt;// Create a DTO.Order from the L2S.Order&lt;br /&gt;DTO.Order order =&lt;br /&gt;(from o in db.Orders&lt;br /&gt;where o.OrderID == orderID&lt;br /&gt;select new DTO.Order&lt;br /&gt;{&lt;br /&gt;OrderID = o.OrderID,&lt;br /&gt;CustomerID = o.CustomerID,&lt;br /&gt;CustomerName = o.Customer.ContactName,&lt;br /&gt;OrderDate = o.OrderDate,&lt;br /&gt;Updated = o.Updated.ToArray(),&lt;br /&gt;OrderDetails =&lt;br /&gt;(from od in o.Order_Details&lt;br /&gt;select new DTO.OrderDetail&lt;br /&gt;{&lt;br /&gt;OrderID = od.OrderID,&lt;br /&gt;ProductID = od.ProductID,&lt;br /&gt;ProductName = od.Product.ProductName,&lt;br /&gt;Quantity = od.Quantity,&lt;br /&gt;UnitPrice = od.UnitPrice,&lt;br /&gt;Updated = od.Updated.ToArray()&lt;br /&gt;}).ToList()&lt;br /&gt;}).Single();&lt;br /&gt;return order;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;　　现在让我们回到 EntityDataProvider 的 GetOrder 方法，该方法使用 LINQ to Entities 基于 L2E.Order 返回 DTO.Order（请参见图 5）。注意，&lt;b&gt;Include&lt;/b&gt; 运算符用于预先加载 Order_Details 和 Order_Details.Product 属性。（有关 LINQ 运算符的详细信息，请参见数据点专栏“LINQ 的标准查询运算符”）。Entity Framework和 LINQ to SQL 都没有提供现成的延迟加载功能，因此您必须明确指出希望在查询结果中包含哪些相关实体。检索到指定的订单之后，您可以直接使用它来创建新的 DTO.Order。 &lt;p&gt;图 5 GetOrder 方法使用 LINQ to Entities 返回 DTO.Order  &lt;p&gt;namespace DataAccessLayer&lt;br /&gt;{&lt;br /&gt;using DataAccessLayer.L2E;&lt;br /&gt;using DTO = DataTransferObjects;&lt;br /&gt;public class EntityDataProvider : IDataProvider&lt;br /&gt;{&lt;br /&gt;public DTO.Order GetOrder(int orderID)&lt;br /&gt;{&lt;br /&gt;using (NorthwindEntities db = new NorthwindEntities&lt;br /&gt;(Settings.Default.NorthwindEntityConnection))&lt;br /&gt;{&lt;br /&gt;// Get the specified L2E.Order&lt;br /&gt;Order nwOrder =&lt;br /&gt;(from o in db.OrderSet&lt;br /&gt;.Include(&amp;quot;Order_Details&amp;quot;)&lt;br /&gt;.Include(&amp;quot;Order_Details.Product&amp;quot;)&lt;br /&gt;where o.OrderID == orderID&lt;br /&gt;select o).First();&lt;br /&gt;// Create a DTO.Order from the L2E.Order&lt;br /&gt;DTO.Order order = new DTO.Order&lt;br /&gt;{&lt;br /&gt;CustomerID = nwOrder.CustomerID,&lt;br /&gt;CustomerName = (from c in db.CustomerSet&lt;br /&gt;where c.CustomerID == nwOrder.CustomerID&lt;br /&gt;select c).First().ContactName,&lt;br /&gt;OrderID = nwOrder.OrderID,&lt;br /&gt;OrderDate = nwOrder.OrderDate,&lt;br /&gt;Updated = nwOrder.Updated,&lt;br /&gt;OrderDetails =&lt;br /&gt;(from od in nwOrder.Order_Details&lt;br /&gt;select new DTO.OrderDetail&lt;br /&gt;{&lt;br /&gt;OrderID = od.OrderID,&lt;br /&gt;ProductID = od.ProductID,&lt;br /&gt;ProductName = od.Product.ProductName,&lt;br /&gt;Quantity = od.Quantity,&lt;br /&gt;UnitPrice = od.UnitPrice,&lt;br /&gt;Updated = od.Updated&lt;br /&gt;}).ToList()&lt;br /&gt;};&lt;br /&gt;return order;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;持久化各个对象 &lt;p&gt;LINQ to SQL 和Entity Framework采用不同的方法持久化断开连接的实体。例如，假设您希望创建具有一个或多个订单明细的新订单。如图 6 所示，LINQ to SQL 至少需要两行代码：一行代码调用 InsertOnSubmit 以插入订单，一行代码使用 InsertAllOnSubmit 插入订单的明细项目。而Entity Framework只需要您将订单添加到 ObjectContext 的 OrderSet，它会自动添加完整的对象图表（请参见图 7）。LINQ to SQL 和Entity Framework都采用以下操作过程：首先插入父订单、获取 OrderID 值（数据库中的标识列），然后插入子订单明细。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_3.gif" width="1" height="1" /&gt;图 6 使用 LINQ to SQL 创建订单 &lt;p&gt;public DTO.Order CreateOrder(DTO.Order order)&lt;br /&gt;{&lt;br /&gt;// Insert new order&lt;br /&gt;using (NorthwindDataContext db = new NorthwindDataContext&lt;br /&gt;(Settings.Default.NorthwindSqlConnection))&lt;br /&gt;{&lt;br /&gt;// Create an L2S.Order&lt;br /&gt;Order nwOrder = new Order&lt;br /&gt;{&lt;br /&gt;OrderID = order.OrderID,&lt;br /&gt;CustomerID = order.CustomerID,&lt;br /&gt;OrderDate = order.OrderDate,&lt;br /&gt;Updated = order.Updated&lt;br /&gt;};&lt;br /&gt;// Add order details&lt;br /&gt;nwOrder.Order_Details.AddRange(&lt;br /&gt;from od in order.OrderDetails&lt;br /&gt;select new Order_Detail&lt;br /&gt;{&lt;br /&gt;OrderID = od.OrderID,&lt;br /&gt;ProductID = od.ProductID,&lt;br /&gt;Quantity = od.Quantity,&lt;br /&gt;UnitPrice = od.UnitPrice,&lt;br /&gt;Updated = od.Updated&lt;br /&gt;});&lt;br /&gt;// Insert order and order details separately&lt;br /&gt;db.Orders.InsertOnSubmit(nwOrder);&lt;br /&gt;db.Order_Details.InsertAllOnSubmit(nwOrder.Order_Details);&lt;br /&gt;db.SubmitChanges();&lt;br /&gt;// Return the updated order&lt;br /&gt;return GetOrder(nwOrder.OrderID);&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_4.gif" width="1" height="1" /&gt;图 7 使用 LINQ to Entities 创建订单 &lt;p&gt;public DTO.Order CreateOrder(DTO.Order order)&lt;br /&gt;{&lt;br /&gt;using (NorthwindEntities db = new NorthwindEntities&lt;br /&gt;(Settings.Default.NorthwindEntityConnection))&lt;br /&gt;{&lt;br /&gt;// Create an L2E.Order&lt;br /&gt;Order nwOrder = new Order&lt;br /&gt;{&lt;br /&gt;OrderID = order.OrderID,&lt;br /&gt;CustomerID = order.CustomerID,&lt;br /&gt;OrderDate = order.OrderDate,&lt;br /&gt;Updated = order.Updated&lt;br /&gt;};&lt;br /&gt;// Add order details&lt;br /&gt;foreach (DTO.OrderDetail od in order.OrderDetails)&lt;br /&gt;{&lt;br /&gt;Order_Detail detail = new Order_Detail&lt;br /&gt;{&lt;br /&gt;Order = nwOrder,&lt;br /&gt;Product = (from p in db.ProductSet&lt;br /&gt;where p.ProductID == od.ProductID&lt;br /&gt;select p).First(),&lt;br /&gt;Quantity = od.Quantity,&lt;br /&gt;UnitPrice = od.UnitPrice,&lt;br /&gt;Updated = od.Updated&lt;br /&gt;};&lt;br /&gt;nwOrder.Order_Details.Add(detail);&lt;br /&gt;}&lt;br /&gt;// Add order and order details&lt;br /&gt;db.AddToOrderSet(nwOrder);&lt;br /&gt;db.SaveChanges();&lt;br /&gt;// Return the updated order&lt;br /&gt;return GetOrder(nwOrder.OrderID);&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;　　在介绍删除或更新实体之前，我需要首先介绍一下如何处理并发问题。LINQ to SQL 要求您附加一个断开连接的实体才能调用 DeleteOnSubmit。这样做系统会提示您使用 LINQ to SQL 执行最优的并发检查，如果用户尝试删除其他用户已经更改的项目，则删除将会失败，并发出 ChangeConflictException。实际上确实没有简单方法可以关闭此行为，因为如果您尝试在不调用 Attach 的情况下调用 DeleteOnSubmit，LINQ to SQL 将会引发 InvalidOperationException。但是，Entity Framework并不强制您在删除实体时处理更改冲突（请参阅本文附带的代码下载）。 &lt;p&gt;　　图 8 显示了使用 LINQ to SQL 更新订单的代码。请注意，Attach 方法接受 bool 类型的 asModified 参数。对 LINQ to SQL 来说，将此参数设置为“True”表示您希望将时间戳列用于并发管理。这样做会使 LINQ to SQL 将当前的时间戳值包含到 SQL Update 语句的 WHERE 子句中。当其他用户更新此记录时，此更新不会影响任何行，并且 LINQ to SQL 将引发 ChangeConflictException。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_5.gif" width="1" height="1" /&gt;图 8 使用 LINQ to SQL 更新订单 &lt;p&gt;public DTO.Order UpdateOrder(DTO.Order order)&lt;br /&gt;{&lt;br /&gt;using (NorthwindDataContext db = new NorthwindDataContext&lt;br /&gt;(Settings.Default.NorthwindSqlConnection))&lt;br /&gt;{&lt;br /&gt;// Create an L2S.Order&lt;br /&gt;Order nwOrder = new Order&lt;br /&gt;{&lt;br /&gt;OrderID = order.OrderID,&lt;br /&gt;CustomerID = order.CustomerID,&lt;br /&gt;OrderDate = order.OrderDate,&lt;br /&gt;Updated = order.Updated&lt;br /&gt;};&lt;br /&gt;// Attach and save order&lt;br /&gt;db.Orders.Attach(nwOrder, true);&lt;br /&gt;db.SubmitChanges();&lt;br /&gt;// Return the updated order&lt;br /&gt;return GetOrder(order.OrderID);&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;　　使用此策略，客户端既不需要保留原始值也不需要将其随更新一起提交，而是将这些值传递到 Attach 方法的其他重载。系统对此列的命名方式没有要求，只需包含时间戳数据类型即可。当您将具有时间戳列的表添加到 Visual Studio 的 LINQ to SQL 设计器之后，所有实体字段的 UpdateCheck 属性将设置为 Never，并且 LINQ to SQL 将使用时间戳来检查更改冲突。 &lt;p&gt;　　当前，相对于 LINQ to SQL 来说，使用Entity Framework更新实体和管理并发稍微有些复杂，因为即使在并发管理中使用时间戳列，它也需要实体的原始值（请参见图 9）。（这一方面可能会在Entity Framework的下一版本中获得改善。）由于客户端未提供原始订单，您需要从数据库中检索此订单并将其 Updated 属性设置为客户端提供的值，此“原始”值才是您真正需要的值。请确保提交对 Updated 的更改，&lt;b&gt;方法为：分离并重新将订单附加到对象上下文，或者调用&lt;/b&gt;&lt;b&gt; AcceptAllChanges&lt;/b&gt;。然后，调用 ApplyPropertyChanges 使用更新订单所提供的值更新原始订单。此外，还需要执行一个步骤，Entity Framework才能使用时间戳列进行并发检查：即，在 Order 实体上将 Updated 属性的 ConcurrencyMode 值从“None”设置为“Fixed”（请参见图 10）。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_6.gif" width="1" height="1" /&gt;图 9 使用 LINQ to Entities 更新订单 &lt;p&gt;public DTO.Order UpdateOrder(DTO.Order order)&lt;br /&gt;{&lt;br /&gt;using (NorthwindEntities db = new NorthwindEntities&lt;br /&gt;(Settings.Default.NorthwindEntityConnection))&lt;br /&gt;{&lt;br /&gt;// Get original order using key from updated order&lt;br /&gt;EntityKey key = db.CreateEntityKey(&amp;quot;OrderSet&amp;quot;,&lt;br /&gt;new Order { OrderID = order.OrderID });&lt;br /&gt;Order origOrder = db.GetObjectByKey(key) as Order;&lt;br /&gt;// Set Updated to match DTO.Order - (for concurrency)&lt;br /&gt;origOrder.Updated = order.Updated;&lt;br /&gt;// Commit change to the Updated property&lt;br /&gt;db.Detach(origOrder);&lt;br /&gt;db.Attach(origOrder);&lt;br /&gt;// Create a NW order for updating the original order&lt;br /&gt;Order updatedOrder = new Order&lt;br /&gt;{&lt;br /&gt;OrderID = order.OrderID,&lt;br /&gt;OrderDate = order.OrderDate,&lt;br /&gt;CustomerID = order.CustomerID,&lt;br /&gt;Updated = order.Updated&lt;br /&gt;};&lt;br /&gt;// Apply changes to the original order&lt;br /&gt;db.ApplyPropertyChanges(&amp;quot;OrderSet&amp;quot;, updatedOrder);&lt;br /&gt;// Persist changes&lt;br /&gt;db.SaveChanges();&lt;br /&gt;// Return the updated order&lt;br /&gt;return GetOrder(order.OrderID);&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image004.gif" width="361" height="394" /&gt; &lt;p&gt;　　图 10 将 Updated 的 ConcurrencyMode 设置为“Fixed” &lt;p&gt;　　跨服务边界跟踪更改 &lt;p&gt;如果您希望仅调用服务一次即可在同一事务中持久化多个实体的更改，您需要使用一种方法来确定每个实体的更改状态。这就是示例应用程序中的每个 DTO 都包含 TrackingState 属性的原因。如果客户端已经设置了此属性，DAL 即可以使用合适的 LINQ to SQL 或Entity Framework API 持久化对断开连接的实体的插入、更新和删除。这样做允许将 DTO 数组传递到服务操作进行&lt;b&gt;批量&lt;/b&gt;更新，以便使用简单的 LINQ to Objects 查询找到插入、更新或删除的订单明细。例如，要想只获得添加到订单的订单明细，您可以使用 TrackingState Created 在集合中查询此类项目： &lt;p&gt;List&amp;lt;Order_Detail&amp;gt; insertedDetails =&lt;br /&gt;(from od in order.OrderDetails&lt;br /&gt;where od.TrackingState == TrackingInfo.Created&lt;br /&gt;select new Order_Detail&lt;br /&gt;{&lt;br /&gt;OrderID = od.OrderID,&lt;br /&gt;ProductID = od.ProductID,&lt;br /&gt;Quantity = od.Quantity,&lt;br /&gt;UnitPrice = od.UnitPrice,&lt;br /&gt;Updated = od.Updated == null ? new byte[0] : od.Updated&lt;br /&gt;}).ToList(); &lt;p&gt;您必须将 Updated 的 null 值转换为空字节数组，因为数据库表中的时间戳列通常不能为空。获得插入的订单明细的列表后，您可以使用合适的 LINQ to SQL API 通过传递订单明细集合来添加新实体： &lt;p&gt;db.Order_Details.InsertAllOnSubmit(insertedDetails); &lt;p&gt;　　和您预想的一样，有 AttachAllOnSubmit 和 DeleteAllOnSubmit 方法可满足您的需要。当对 DataContext 调用 SubmitChanges 时，LINQ to SQL 会确保按正确的顺序提交这些更改（对插入项目使用父子顺序，对删除项目使用子父顺序），并且将所有的操作包含在一个事务中。您可以借助相同的方法使用 LINQ to Entities 持久化订单明细。有关适用于 LINQ to SQL 和Entity Framework的 UpdateOrder 的完整代码列表，请参阅下载内容。 &lt;p&gt;　　现在，很明显就可以看出 DAL 依靠客户端跟踪每个 DTO 的更改状态。客户端上跟踪对象更改的最方便机制是泛型集合。为了使集合能够更新 TrackingState 属性，应该约束类型参数以实现接口。（您还可以使用 Reflection 获得和设置 TrackingState 属性，但泛型类型约束可提供类型安全性和更好的性能。）输入只包含 TrackingState 属性的 ITrackable 接口： &lt;p&gt;public interface ITrackable&lt;br /&gt;{&lt;br /&gt;TrackingInfo TrackingState { get; set; }&lt;br /&gt;} &lt;p&gt;　　正如我前面提及到的，跟踪更改集合有两种类型：一种用于 Windows 窗体，扩展 BindingList&amp;lt;T&amp;gt;；一种用于 WPF 应用程序，扩展 ObservableCollection&amp;lt;T&amp;gt;。我并没有在这两个集合中重复更改跟踪逻辑，而是将此逻辑集中到 ChangeTrackingHelper&amp;lt;T&amp;gt; 类中，此类从 Collection&amp;lt;T&amp;gt; 派生并约束 T 以实现 ITrackable（请参见图 11）。此外，它还约束 T 以实现 INotifyPropertyChanged，以便处理每个项目的 PropertyChanged 事件以及将 TrackingState 属性设置为 Updated。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_7.gif" width="1" height="1" /&gt;图 11 更改跟踪帮助程序类 &lt;p&gt;internal class ChangeTrackingHelper&amp;lt;T&amp;gt; : Collection&amp;lt;T&amp;gt;&lt;br /&gt;where T : ITrackable, INotifyPropertyChanged&lt;br /&gt;{&lt;br /&gt;Collection&amp;lt;T&amp;gt; deletedItems = new Collection&amp;lt;T&amp;gt;();&lt;br /&gt;// Listen for changes to each item&lt;br /&gt;private bool tracking;&lt;br /&gt;public bool Tracking&lt;br /&gt;{&lt;br /&gt;get { return tracking; }&lt;br /&gt;set&lt;br /&gt;{&lt;br /&gt;foreach (T item in this)&lt;br /&gt;{&lt;br /&gt;if (value) item.PropertyChanged += OnItemChanged;&lt;br /&gt;else item.PropertyChanged -= OnItemChanged;&lt;br /&gt;}&lt;br /&gt;tracking = value;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;void OnItemChanged(object sender, PropertyChangedEventArgs e)&lt;br /&gt;{&lt;br /&gt;if (!Tracking) return;&lt;br /&gt;ITrackable item = (ITrackable)sender;&lt;br /&gt;if (e.PropertyName != &amp;quot;TrackingState&amp;quot;)&lt;br /&gt;{&lt;br /&gt;// Mark item as updated&lt;br /&gt;if (item.TrackingState == TrackingInfo.Unchanged)&lt;br /&gt;item.TrackingState = TrackingInfo.Updated;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;// Mark item as created and listen for property changes&lt;br /&gt;protected override void InsertItem(int index, T item)&lt;br /&gt;{&lt;br /&gt;if (!Tracking) return;&lt;br /&gt;item.TrackingState = TrackingInfo.Created;&lt;br /&gt;item.PropertyChanged += OnItemChanged;&lt;br /&gt;base.InsertItem(index, item);&lt;br /&gt;}&lt;br /&gt;// Mark item as deleted and cache it&lt;br /&gt;protected override void RemoveItem(int index)&lt;br /&gt;{&lt;br /&gt;if (!Tracking) return;&lt;br /&gt;T item = this.Items[index];&lt;br /&gt;if (item.TrackingState != TrackingInfo.Created)&lt;br /&gt;{&lt;br /&gt;item.TrackingState = TrackingInfo.Deleted;&lt;br /&gt;item.PropertyChanged -= OnItemChanged;&lt;br /&gt;deletedItems.Add(item);&lt;br /&gt;}&lt;br /&gt;base.RemoveItem(index);&lt;br /&gt;}&lt;br /&gt;public ChangeTrackingHelper&amp;lt;T&amp;gt; GetChanges()&lt;br /&gt;{&lt;br /&gt;// Create a collection with changed items&lt;br /&gt;ChangeTrackingHelper&amp;lt;T&amp;gt; changes = new ChangeTrackingHelper&amp;lt;T&amp;gt;();&lt;br /&gt;foreach (T existing in this)&lt;br /&gt;{&lt;br /&gt;if (existing.TrackingState != TrackingInfo.Unchanged)&lt;br /&gt;changes.Add(existing);&lt;br /&gt;}&lt;br /&gt;// Append deleted items&lt;br /&gt;foreach (T deleted in deletedItems)&lt;br /&gt;changes.Add(deleted);&lt;br /&gt;return changes;&lt;br /&gt;}&lt;br /&gt;} &lt;p&gt;　　将项目添加到集合后，其 TrackingState 将设置为 Created。项目删除后，其 TrackingState 将设置为 Deleted，并缓存在已删除项目的集合中。在进行跟踪之前，用户应该首先将集合的 Tracking 属性设置为 True，以便集合订阅每个项目的 PropertyChanged 事件。GetChanges 方法会创建一个新的 ChangeTrackingHelper 集合，其中仅包含标记为创建、更新或删除的项目。 &lt;p&gt;　　配置客户端 &lt;p&gt;我们已经了解了一组通用的跟踪更改集合，现在可以派上用场了！我已将这些集合放置在一个单独类库中，因此您只需从客户端应用程序中引用即可。但是，当您向客户端项目添加服务引用时，您必须执行一些其他步骤，集合才能使用 svcutil.exe 生成的类。虽然 Customer、Product、Order 和 OrderDetails 等类已经具有了 TrackingState 属性，但它们不会实现 ChangeTrackingHelper&amp;lt;T&amp;gt; 所需的 ITrackable 接口。 &lt;p&gt;　　另外，必须将 TrackingInfo 枚举放置在跟踪更改集合可以找到的命名空间，但不是嵌套命名空间，因为 svcutil.exe 会在您添加服务引用时将其置于此处。最后，如果服务操作返回的对象数组在客户端应用程序中显示为跟踪更改集合，那就更好了。因为这样会使 Order.OrderDetails 的数据类型设置为 ChangeTrackingCollection&amp;lt;T&amp;gt; 或 ChangeTrackingList&amp;lt;T&amp;gt;（而非 OrderDetail 数组），从而减少向服务发送已更改的订单明细的工作量。 &lt;p&gt;　　要设置 Windows 窗体或 WPF 客户端应用程序，使其使用跟踪更改集合跟踪实体更改并将这些更改发送至服务，需要遵循以下步骤。务必按照给定顺序执行以下步骤： &lt;p&gt;　　在 Windows 窗体或 WPF 客户端应用程序中，设置对 ClientChangeTracker 类库项目或程序集（ITrackable 接口和跟踪更改集合放置位置）的引用。 &lt;p&gt;　　在 WCF 服务应用程序运行的过程中，添加指向元数据终点或 Web 服务描述语言 (WSDL) URL 的服务引用。在添加服务引用之前，引用 ClientChangeTracker 程序集非常重要。默认情况下，服务引用将重用所有引用程序集中的类型，并且由于 ClientChangeTracker 包含的 TrackingInfo 枚举具有 DataContract 和 EnumMember 序列化属性，svcutil.exe 会重用此枚举而不会将其复制到服务引用创建的 Reference.cs 代码文件中。 &lt;p&gt;　　设置服务引用之后，为服务引用创建的每个 DTO 类添加局部类。例如，如果您的服务操作公开了 Customer、Product、Order 和 OrderDetail 对象，它们都将包含在服务引用中。如果显示项目的所有文件并展开服务引用和 Reference.svcmap 节点，您会在 Reference.cs 中看到这些类。记下它们所属的命名空间（应该与您添加服务引用时指定的位置一致）。现在将类文件添加到项目中并更改命名空间，以在 Reference.cs 中反映此命名空间。在此命名空间中，为每个 DTO 类添加公共局部类并实现 ITrackable 接口： &lt;p&gt;namespace WpfClient.OrderService&lt;br /&gt;{&lt;br /&gt;public partial class Customer : ITrackable { }&lt;br /&gt;public partial class Product : ITrackable { }&lt;br /&gt;public partial class Order : ITrackable { }&lt;br /&gt;public partial class OrderDetail : ITrackable { }&lt;br /&gt;}注意 TrackingState 属性缺失的情况。由于此属性作为每个 DTO 数据约定的一部分包含在代码生成的类中，因此您无需在此处插入该属性。为了在应用程序中更加轻松地使用这些类，您还可以在这些类中插入其他代码，例如，初始化类的构造函数（使用 new 创建类时调用；WCF 创建类时不调用）。有关示例，请参阅代码下载。 &lt;p&gt;　　最后，您可能希望将服务引用配置为使用 ChangeTrackingCollection&amp;lt;T&amp;gt; 或 ChangeTrackingList&amp;lt;T&amp;gt; 作为集合类型，而不是 System.Array。这表示当服务操作返回 Order 数组时，将在客户端上具体化为 ChangeTrackingCollection&amp;lt;Order&amp;gt; 或 ChangeTrackingList&amp;lt;Order&amp;gt;。每个 Order 的 OrderDetails 属性都有可能显示为跟踪更改集合类型。知道这有多酷了吧？要想实现这种奇妙的转变，您必须打开 Reference.svcmap 文件（显示所有项目文件并打开服务引用进行查看）然后深入研究 XML。对于 WPF 客户端，按如下所示配置 CollectionMappings 元素： &lt;p&gt;&amp;lt;CollectionMappings&amp;gt;&lt;br /&gt;&amp;lt;CollectionMapping TypeName=&amp;quot;ChangeTracker.ChangeTrackingCollection&amp;#39;1&amp;quot; Category=&amp;quot;List&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/CollectionMappings&amp;gt; &lt;p&gt;　　对于 Windows 窗体客户端，您应该将 Change&amp;shy;Track&amp;shy;er.ChangeTrackingCollection`1 替换为 Change&amp;shy;Tracker.Change&amp;shy;Track&amp;shy;ing&amp;shy;List`1。 &lt;p&gt;　　现在，在服务应用程序运行过程中，右键单击服务引用并选择“更新服务引用”，然后重新编译客户端应用程序。如果一切顺利，则会成功构建项目，您将可以继续执行操作。 &lt;p&gt;　　完成这些步骤之后，剩下的就是为客户端应用程序编写代码以检索某些 DTO 并将它们绑定到 UI（用户可以在此处更新 DTO 并将其发送回服务以保存到数据库中）。从服务中检索对象只需要创建一个服务代理实例并调用操作来获取 Customer、Product 和 Order 即可。例如，如果服务包含的 GetOrder 方法接受 Int 类型的 OrderId，那么您的客户端代码可能如下所示： &lt;p&gt;using (OrderServiceClient proxy = new OrderServiceClient())&lt;br /&gt;{&lt;br /&gt;CurrentOrder = proxy.GetOrder(orderId);&lt;br /&gt;} &lt;p&gt;　　如果您的数据绑定设置正确，订单和订单明细都应该显示在用户界面上。图 12 显示了示例应用程序在 WPF 客户端中的显示。单击“Get Order”按钮，用户可以检索某个现有订单，以及从客户订单列表中进行选择；单击“New Order”按钮可直接创建新订单；单击“Delete Order”按钮，用户可对服务器代理调用 DeleteOrder，从而删除当前订单。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image005.gif" width="400" height="340" /&gt; &lt;p&gt;　　图 12 示例 WPF 客户端应用程序 &lt;p&gt;　　单击“Save Order”按钮，可以调用服务 CreateOrder 操作以持久化最新创建的订单，或调用 UpdateOrder 操作保存对现有订单的更改。这两种操作都会返回一个订单对象，其中包含用于并发管理的当前 Updated 属性和用于插入订单的新 OrderId 属性（Northwind 中 Order 表使用标识列）。获得更新订单后，您即可以启动更改跟踪并将数据绑定设置为使用订单。 &lt;p&gt;　　但是，在保存现有的订单之前，您还需要执行一些操作。我们只希望传递创建、更新或删除的订单明细，而不想浪费网络带宽来发送未发生更改的订单明细。借助 ChangeTrackingCollection&amp;lt;T&amp;gt; 和 ChangeTrackingList&amp;lt;T&amp;gt; 可以比较轻松地实现此目的，因为它们公开的 GetChanges 方法只返回插入、修改或删除的订单明细。调用 UpdateOrder 的代码如图 13 所示。 &lt;p&gt;&lt;img alt="SOA 数据访问：使用 LINQ To SQL 和实体框架实现灵活的数据访问" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/clip_5F00_image003_5F00_8.gif" width="1" height="1" /&gt;图 13 调用 UpdateOrder  &lt;p&gt;Order changedOrder = new Order&lt;br /&gt;{&lt;br /&gt;OrderID = CurrentOrder.OrderID,&lt;br /&gt;CustomerID = CurrentOrder.CustomerID,&lt;br /&gt;OrderDate = CurrentOrder.OrderDate,&lt;br /&gt;Updated = CurrentOrder.Updated,&lt;br /&gt;TrackingState = CurrentOrder.TrackingState,&lt;br /&gt;OrderDetails = CurrentOrder.OrderDetails.GetChanges()&lt;br /&gt;};&lt;br /&gt;using (OrderServiceClient proxy = new OrderServiceClient())&lt;br /&gt;{&lt;br /&gt;CurrentOrder = proxy.UpdateOrder(changedOrder);&lt;br /&gt;} &lt;p&gt;　　由于我已经将服务引用配置为使用 ChangeTrackingCollection&amp;lt;T&amp;gt; 作为集合类型，因此 Order 类的 OrderDetails 属性应该属于类型 ChangeTrackingCollection&amp;lt;OrderDetail&amp;gt;，并且我可以直接对其调用 GetChanges 只获得添加、修改或删除的订单细节，以传递给 UpdateOrder 操作。另外，由于 ChangeTrackingCollection&amp;lt;T&amp;gt; 可扩展 ObservableCollection&amp;lt;T&amp;gt;，因此它支持的数据绑定功能非常适用于 WPF 应用程序（例如，实现 INotifyCollectionChanged 以便在向集合添加或从集合删除项目时 UI 可以更新项目控件）。同理，由于 ChangeTrackingList&amp;lt;T&amp;gt; 可扩展 BindingList&amp;lt;T&amp;gt;，它可以作为 Windows 窗体 DataGridView 的有效数据源，以利用 BindingList&amp;lt;T&amp;gt; 实现的接口增强用户体验。 &lt;p&gt;　　总结 &lt;p&gt;　　现在您已经拥有了一个面向服务的灵活应用程序体系结构，在此体系结构中，客户端可以完全不考虑对象的持久化方法。我们知道，DTO 允许对对象模型的结构和形状进行更多的控制，这与允许跨服务边界传递工具生成的实体一样具有吸引力。此外，构建数据访问层可将应用程序从您使用的任何持久性技术中分离出来，从而允许您在不影响应用程序的其他部分的情况下更换数据访问实现。 &lt;p&gt;LINQ to SQL 和 ADO.NET Entity Framework的出现代表了 ORM 领域的一次巨大飞跃，有效地减少了对象和关系数据之间的阻抗失谐。它们支持各种方案，包括传统客户端服务器和面向服务的体系结构。但是，对于开发人员来说，使用 DTO 更新数据库需要进行更多的工作，尤其是在使用时间戳值检测并发用户之间的冲突时。但是，通过将更改状态添加到客户端和服务之间的数据约定，您可以附加与源上下文断开连接的实体。最后，我们介绍了通用的跟踪更改集合如何不负众望地管理客户端上的更改状态，使您访问服务一次即可处理批更新。&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=191" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author><category term="Entity Framework" scheme="http://community.icburner.com/blogs/webdev/archive/tags/Entity+Framework/default.aspx" /><category term="POCO" scheme="http://community.icburner.com/blogs/webdev/archive/tags/POCO/default.aspx" /></entry><entry><title>新的项目架构实现要考虑的方面</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/29/185.aspx" /><id>/blogs/webdev/archive/2009/05/29/185.aspx</id><published>2009-05-29T04:38:00Z</published><updated>2009-05-29T04:38:00Z</updated><content type="html">&lt;p&gt;通过最近一段时期对Entity Framework和ASP.NET MVC的学习，初步总结出要设计一个新项目所需考虑的方面：&lt;/p&gt;
&lt;h3&gt;一、数据建模：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;存储层数据建模：Entity对象（Entity Objects）。包括：Entity、EntityCollection对象。&lt;/li&gt;
&lt;li&gt;域模型设计（DDD）：POCO对象（DTO Objects）、状态跟踪（State Tracking）、数据验证模型Validators。包括：Object、IList对象。&lt;/li&gt;
&lt;li&gt;展现层建模：视图模型（View Models）、JSON、JQuery封装。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;二、架构实现：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;实现底层Repository层：封装Entity Framework数据模型，采用仓储（&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;Repositories）、查询准则（&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;Specifications）、载入策略（&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;Fetching Strategies&lt;/span&gt;）获取实体对象（Entity Objects）、操作POCO对象（DTO Objects）与实体对象（EntityObjects）的转换。&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;中间Service层：封装对POCO的操作，它依赖&lt;span style="font-family:Arial;font-size:x-small;"&gt;Repository层。实现事务Transaction功能。&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="font-family:Arial;font-size:x-small;"&gt;界面展现层：ASP.NET MVC定制扩展。包括：Controllers、Validation、Filters、ModelBinders、MVC控件、分页器（Pagenation）等等。&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="font-family:Arial;font-size:x-small;"&gt;Data-Layer: EF + Repository Object&lt;br /&gt;&lt;br /&gt;Business Layer: B.Objects for each major Entity with Validation and Domain Logic (*made it fine to here with IUpdateable,etc*)&lt;br /&gt;&lt;br /&gt;Service Layer: Ado.Net Data Service exposing the Entities as DTO&amp;#39;s but from the B.O&amp;#39;s logic, not EFs, so I have more control over what it does.&lt;br /&gt;&lt;br /&gt;Model Layer: Handle making requests to my SOA Services&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="line-height:115%;font-family:&amp;#39;Calibri&amp;#39;,&amp;#39;sans-serif&amp;#39;;font-size:11pt;mso-bidi-font-family:&amp;#39;Times New Roman&amp;#39;;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA;"&gt;&lt;span style="font-family:Arial;font-size:x-small;"&gt;Controller Layer: View Layer with Javascript&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://community.icburner.com/aggbug.aspx?PostID=185" width="1" height="1"&gt;</content><author><name>communityadmin</name><uri>http://community.icburner.com/members/communityadmin/default.aspx</uri></author></entry><entry><title>INTRODUCING F#</title><link rel="alternate" type="text/html" href="/blogs/webdev/archive/2009/05/27/benefits-of-f.aspx" /><id>/blogs/webdev/archive/2009/05/27/benefits-of-f.aspx</id><published>2009-05-27T06:20:10Z</published><updated>2009-05-27T06:20:10Z</updated><content type="html">&lt;h3&gt;第一篇，从零开始编写我们的第一个F#程序。&lt;/h3&gt;  &lt;p&gt;&lt;strong&gt;什么是F#，我为何要学它？&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#是一种.NET平台上的&lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;函数式编程&lt;/a&gt;语言。就像C#和VB.NET，F#可以利用.NET的核心类库，如&lt;a href="http://msdn.microsoft.com/en-us/netframework/aa663326.aspx"&gt;WPF&lt;/a&gt;，&lt;a href="http://msdn.microsoft.com/en-us/netframework/aa663324.aspx"&gt;WCF&lt;/a&gt;，&lt;a href="http://msdn.microsoft.com/en-us/office/aa905533.aspx"&gt;VSTO&lt;/a&gt;等等，通过F#您甚至可以使用&lt;a href="http://msdn.microsoft.com/en-us/xna/default.aspx"&gt;XNA&lt;/a&gt;编写XBox游戏。&lt;/p&gt;  &lt;p&gt;仅仅如此并不意味着您应该去学习它。那为何要使用F#呢？作为一种函数式编程语言，F#使得某些领域的编程要比命令式编程（如使用C#）更为容易。并行编程（Parallel Programming）和面向语言编程（Language-Oriented Programming）是其中的两个领域。&lt;/p&gt;  &lt;p&gt;如果您曾经编写过.NET应用程序，并感觉自己在努力使用手头的语言表达自己的想法，也许F#就是您在寻找的。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;上路&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;首先得&lt;a href="http://research.microsoft.com/research/downloads/Details/7ac148a7-149b-4056-aa06-1e6754efd36f/Details.aspx"&gt;下载&lt;/a&gt;（F#的最新版本1.9.4.19）和安装。安装程序会在VS2005和VS2008中安装F#的项目系统（项目模板和项模板）。先来创建一个新的F#项目。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_2.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb.png" width="532" height="376" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;然后添加一个新的F#源文件file1.fs。默认条件下，新建的源文件包含了很多&amp;#8220;教学&amp;#8221;代码，全部删除，然后输入下面的代码：&lt;/p&gt;  &lt;p&gt;#light   &lt;br /&gt;let square x = x * x    &lt;br /&gt;let numbers = [1 .. 10]    &lt;br /&gt;let squares = List.map square numbers    &lt;br /&gt;printfn &amp;quot;N^2 = %A&amp;quot; squares    &lt;br /&gt;open System    &lt;br /&gt;Console.ReadKey(true) &lt;/p&gt;  &lt;p&gt;按下F5运行程序，您会看到：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_4.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_1.png" width="562" height="307" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;这些并没有太多让人兴奋的。我们来逐行的分析下代码，看看到底有什么不同之处，在此之前先介绍下VFSI。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Visual Studio中的F#交互（Interactive）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#交互控制台（F# Interactive Console, FSI）采用的是&amp;#8220;REPL loop&amp;#8221;模式，即Read-Evaluate-Print-Loop。也就是输入一段代码，编译并执行，然后输出结果。通过它您可以快速地开发和测试程序。要在VS中启用FSI，打开Add-in Manager窗口。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_6.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_2.png" width="436" height="378" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;选中&amp;#8220;F# Inactive for Visual Studio&amp;#8221;。然后，选中程序的前两行代码：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_8.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_3.png" width="252" height="102" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;接着按下Alt+Enter（实际上，如果FSI还么有打开，需要按两次Alt+Enter）。这时会看到出现了一个工具窗口：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_10.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_4.png" width="488" height="397" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;我们刚才做的事情是将代码片段直接发送给FSI会话，FSI将结果输出。结果是函数&amp;#8220;square&amp;#8221;的定义，它接受int类型参数，返回类型也是int。&lt;/p&gt;  &lt;p&gt;接下来在FSI窗口输入&amp;#8220;List.map square [1 .. 2 .. 10];;&amp;#8221;。&amp;#8220;;;&amp;#8221;是告诉FSI停止阅读程序，立即进行求值。&lt;/p&gt;  &lt;p&gt;&amp;gt; List.map square [1 .. 2 .. 10];;   &lt;br /&gt;val it : int list = [1; 9; 25; 49; 81] &lt;/p&gt;  &lt;p&gt;现在我们可以方便地通过FSI来学习F#了，马上来看看我们的程序究竟做了什么吧。不过仍建议您在VS源代码编辑器中输入代码，使用&amp;#8220;Select（原文是Highlight，感觉Select更贴切） + Alt + Enter&amp;#8221;将代码片段发送至FSI。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;语言基础&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;#light（OCaml兼容）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#源自OCaml，具有交互编译OCaml的能力，也就是可以不经修改即可编译简单的OCaml程序。这种能力也带来了令人讨厌的语法。#light（发音为hash-light）是一个编译器指令，可以简化F#的语法。&lt;/p&gt;  &lt;p&gt;强烈建议您保持使用#light，您会发现，在大多数F#代码片段中要么会声明它，要么是假定已经声明了它。 &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;let square x = x * x（类型推演）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;这行代码定义了一个函数：square，它会求得数字x的平方。考虑一下C#中等价的代码：&lt;/p&gt;  &lt;p&gt;public static int square(int x)   &lt;br /&gt;{    &lt;br /&gt;return x * x;    &lt;br /&gt;}&lt;/p&gt;  &lt;p&gt;在C#中，您需要制定参数和返回值的类型信息，而F#则帮您搞定了。这种行为称为&lt;strong&gt;类型推演（Type Inference）&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;从函数的签名，F#可以知道&amp;#8220;square&amp;#8221;函数接受一个参数&amp;#8220;x&amp;#8221;，并且函数返回&amp;#8220;x * x&amp;#8221;（在函数体内的最后一次求值将作为返回值，因此无须return关键字）。因为很多基元类型都支持*操作，比如byte，uint64，double等，F#默认会使用int类型，有符号的32位整数。&lt;/p&gt;  &lt;p&gt;现在考虑下面的代码，它为其中的一个参数提供了&amp;#8220;&lt;strong&gt;类型注解（type annotation）&lt;/strong&gt;&amp;#8221;，告诉编译器期望的类型。因为x标为&amp;#8220;string&amp;#8221;，&amp;#8220;+&amp;#8221;操作只定义在两个string间，因此y也必须为string类型，返回值是两个字符串拼接的结果。&lt;/p&gt;  &lt;p&gt;&amp;gt; let concat (x : string) y = x + y;;   &lt;br /&gt;val concat : string -&amp;gt; string -&amp;gt; string    &lt;br /&gt;&amp;gt; concat &amp;quot;Hello, &amp;quot; &amp;quot;World!&amp;quot;;;    &lt;br /&gt;val it : string = &amp;quot;Hello, World!&amp;quot;&lt;/p&gt;  &lt;p&gt;后面我们将讨论类型推演的更多高级主题，现在您只要享受F#编译器的智能带来的方便就好了。 &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;let numbers = [1 .. 10]（F# lists）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;这行代码声明了一个列表（list），其元素是从1至10。如果您用的是[|1 .. 10|]，F#会创建一个.NET的整型数组（array）。而在F#中，列表是一个不可变的链表（linked list），这也是函数式编程的基础。试着将这些代码输入到FSI中（记住添加&amp;#8220;;;&amp;#8221;）：&lt;/p&gt;  &lt;p&gt;// Define a list&amp;#160; &lt;br /&gt;let vowels = [&amp;#39;e&amp;#39;; &amp;#39;i&amp;#39;; &amp;#39;o&amp;#39;; &amp;#39;u&amp;#39;]&amp;#160; &lt;br /&gt;// Attach item to front (cons)    &lt;br /&gt;let cons = &amp;#39;a&amp;#39; :: vowels&amp;#160; &lt;br /&gt;// Concat two lists    &lt;br /&gt;let sometimes = vowels @ [&amp;#39;y&amp;#39;]&lt;/p&gt;  &lt;p&gt;我将在本系列的第二篇中更深入地介绍列表。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;let squares = List.map square numbers &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;现在我们有了一个整型列表（numbers）和一个函数（square），我们希望创建一个新的列表，它的每一项是对numbers的每一项进行square运算后的结果。&lt;/p&gt;  &lt;p&gt;幸运的是，List.map可以做到。考虑下面的例子：&lt;/p&gt;  &lt;p&gt;&amp;gt; List.map (fun x -&amp;gt; x % 2 = 0) [1 .. 10];;   &lt;br /&gt;val it : bool list    &lt;br /&gt;= [false; true; false; true; false; true; false; true; false; true]&lt;/p&gt;  &lt;p&gt;代码（fun x -&amp;gt; x % 2 = 0）定义了一个匿名函数，称为&lt;a href="http://en.wikipedia.org/wiki/Lambda_calculus"&gt;lamdba表达式&lt;/a&gt;，接受一个参数x，返回值为表达式&amp;#8220;x % 2 = 0&amp;#8221;的结果，也就是判断x是否为偶数。&lt;/p&gt;  &lt;p&gt;注意我们刚才做的&amp;#8212;&amp;#8212;将一个函数作为参数传递给另一个函数。在C#中这个并不容易。但在F#可以很清楚地表达出来，而且代码很简洁。将函数像值一样传递被称为&amp;#8220;一等函数（first order functions）&amp;#8221;，也是函数式编程的基础。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;printfn &amp;quot;N^2 = %A&amp;quot; squares&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;printf是打印文本到控制台窗口的一种简单而又类型安全的方式。要更好地了解printf，考虑下面的例子，它打印一个整数、浮点数和字符串。&lt;/p&gt;  &lt;p&gt;&amp;gt; printfn &amp;quot;%d * %f = %s&amp;quot; 5 0.75 ((5.0 * 0.75).ToString());;   &lt;br /&gt;5 * 0.750000 = 3.75    &lt;br /&gt;val it : unit = ()&lt;/p&gt;  &lt;p&gt;%d，%f，%s分别是int、float、string的占位符。%A则可用于打印任何值。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Console.ReadKey(true) (.NET互操作)&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;我们程序的最后一行只是简单地调用了System.Console.ReadKey方法，这样可以让程序在关闭其暂停。因为F#建立在.NET的基础上，您可以在F#中调用任何.NET类库&amp;#8212;&amp;#8212;从正则表达式到WinForms。代码&amp;#8220;open System&amp;#8221;用于打开命名空间，类似于C#中的using。&lt;/p&gt;  &lt;p&gt;现在我们已经有了F#的基础知识，可以继续学习更有趣的基础类型和F#概念了，希望您关注第二篇文章！&lt;/p&gt;  &lt;p&gt;原文链接：&lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/05/02/f-in-20-minutes-part-i.aspx"&gt;http://blogs.msdn.com/chrsmith/archive/2008/05/02/f-in-20-minutes-part-i.aspx&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1.不可变性（Immutability）&lt;/strong&gt;    &lt;br /&gt;您也许已经注意到，我一直使用&amp;#8220;值（value）&amp;#8221;来表示一个标识符（identifier），而不是&amp;#8220;变量（variable）&amp;#8221;。这是由于默认情况下，F#中的类型是不可变的（immutable），也就是说，一经创建即不可修改。看起来这是一个很大的限制，但是不可变性可以避免&lt;a&gt;&lt;/a&gt;&lt;a href="http://blogs.gotdotnet.com/jomo_fisher/archive/2007/05/16/leaky-functions-barrel-of-bugs.aspx"&gt;某种类型的bug&lt;/a&gt;&lt;a href="http://blogs.gotdotnet.com/jomo_fisher/archive/2007/05/16/leaky-functions-barrel-of-bugs.aspx"&gt;&lt;/a&gt;。另外，不可变的数据天然地具备线程安全的特性，这意味着您无需在处理并行情况时担心同步锁的发生。我将在系列的第三篇中介绍异步编程。 &lt;/p&gt;  &lt;p&gt;如果您确实需要修改数据，可使用F#的mutable关键字，它会创建一个变量（而不是值）。我们可以通过左箭头操作符（&amp;lt;-）来修改变量的值。 &lt;/p&gt;  &lt;p&gt;&amp;gt; let mutable x = &amp;quot;the original value.&amp;quot;;;   &lt;br /&gt;val mutable x : string    &lt;br /&gt;&amp;gt; printfn &amp;quot;x&amp;#39;s value is &amp;#39;%s&amp;#39;&amp;quot; x;;    &lt;br /&gt;x&amp;#39;s value is &amp;#39;the original value.&amp;#39;    &lt;br /&gt;val it : unit = ()    &lt;br /&gt;&amp;gt; x &amp;lt;- &amp;quot;the new one.&amp;quot;;;    &lt;br /&gt;val it : unit = ()    &lt;br /&gt;&amp;gt; printfn &amp;quot;x&amp;#39;s value is now &amp;#39;%s&amp;#39;&amp;quot; x;;    &lt;br /&gt;x&amp;#39;s value is now &amp;#39;the new one.&amp;#39;    &lt;br /&gt;val it : unit = ()&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2. 引用值（Reference values，Microsoft.FSharp.Core.Ref&amp;lt;_&amp;gt;）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;引用值是另一种表示可修改数据的方式。但它不是将变量存储在堆栈（stack），引用值其实是一个指向存储在堆（heap）上的变量的指针（pointer）。在F#中使用可修改的值时会有些限制（比如不可以在内部lambda表达式中使用）。而ref对象则可被安全地传递，因为它们是不可变的record值（只是它有一个可修改的字段）。 &lt;/p&gt;  &lt;p&gt;使用引用值时，用&amp;#8220;:=&amp;#8221;赋一个新值，使用&amp;#8220;!&amp;#8221;进行解引用。&lt;/p&gt;  &lt;p&gt;&amp;gt; let refCell = ref 42;;   &lt;br /&gt;val refCell : int ref    &lt;br /&gt;&amp;gt; refCell := -1;;    &lt;br /&gt;val it : unit = ()    &lt;br /&gt;&amp;gt; !refCell;;    &lt;br /&gt;val it : int = &amp;#8211;1&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3. 模块（Modules）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在前面中，我只是随意地声明了几个值和函数。您也许会问，&amp;#8220;要把它们放在哪里呢？&amp;#8221;，因为在C#中所有一切都要属于相应的类。尽管在F#中，我们仍然可以用熟悉的方式声明标准的.NET类，但它也有模块的概念，模块是值、函数和类型的集合（可以对比一下命名空间，后者只能包含类型）。&lt;/p&gt;  &lt;p&gt;这也是我们能够访问&amp;#8220;List.map&amp;#8221;的原因。在F#库（FSharp.Core.dll）中，有一个名为&amp;#8220;List&amp;#8221;的模块，它包含了函数&amp;#8220;map&amp;#8221;。&lt;/p&gt;  &lt;p&gt;在快速开发的过程中，如果不需要花费时间去设计严格的面向对象类型体系，就可以采用模块来封装代码。要声明自己的模块，要使用module关键字。在下面的例子中，我们将为模块添加一个可修改的变量，该变量也是一个全局变量。&lt;/p&gt;  &lt;p&gt;module ProgramSettings =   &lt;br /&gt;let version = &amp;quot;1.0.0.0&amp;quot;    &lt;br /&gt;let debugMode = ref false    &lt;br /&gt;module MyProgram =    &lt;br /&gt;do printfn &amp;quot;Version %s&amp;quot; ProgramSettings.version    &lt;br /&gt;open ProgramSettings    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; debugMode := true&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;4. 元组（Tuples）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;元组（tuple，发音为&amp;#8216;two-pull&amp;#8217;）表示值的有序集合，而这些值可看作一个整体。按传统的方式，如果您要传递一组相关的值，需要创建结构（struct）或类（class），或者还需要&amp;#8220;out&amp;#8221;参数。使用元组我们可以将相关的值组织起来，同时并不需要引入新的类型。&lt;/p&gt;  &lt;p&gt;要定义一个元组，只要将一组值用逗号分隔，并用圆括号把它们括起来即可。&lt;/p&gt;  &lt;p&gt;&amp;gt; let tuple = (1, false, &amp;quot;text&amp;quot;);;   &lt;br /&gt;val tuple : int * bool * string    &lt;br /&gt;&amp;gt; let getNumberInfo (x : int) = (x, x.ToString(), x * x);;    &lt;br /&gt;val getNumberInfo : int -&amp;gt; int * string * int    &lt;br /&gt;&amp;gt; getNumberInfo 42;;    &lt;br /&gt;val it : int * string * int = (42, &amp;quot;42&amp;quot;, 1764)&lt;/p&gt;  &lt;p&gt;函数甚至可以接受元组为参数：&lt;/p&gt;  &lt;p&gt;&amp;gt; let printBlogInfo (owner, title, url) = printfn &amp;quot;%s&amp;#39;s blog [%s] is online at &amp;#39;%s&amp;#39;&amp;quot; owner title url;;&amp;#160; &lt;br /&gt;val printBlogInfo : string * string * string -&amp;gt; unit&amp;#160; &lt;br /&gt;&amp;gt; let myBlog = (&amp;quot;Chris&amp;quot;, &amp;quot;Completely Unique View&amp;quot;, &amp;quot;http://blogs.msdn.com/chrsmith&amp;quot;);;    &lt;br /&gt;val myBlog : string * string * string    &lt;br /&gt;&amp;gt; printBlogInfo myBlog;;    &lt;br /&gt;Chris&amp;#39;s blog [Completely Unique View] is online at &amp;#39;http://blogs.msdn.com/chrsmith&amp;#39;    &lt;br /&gt;val it : unit = ()&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;5. 函数柯里化（Function Currying）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#提供的一个新奇的特性是可以只接受参数的一个子集，而接受部分参数的结果则是一个新的函数。这就是所谓的&amp;#8220;函数柯里化&amp;#8221;。比如，假设有一个函数接受3个整数，返回它们的和。我们可以只传入第一个参数，假设值为10，这样我们就可以说将原来的函数柯里化了，而它会返回一个新的函数&amp;#8212;&amp;#8212;新函数接受两个整数，返回它们与10的和。&lt;/p&gt;  &lt;p&gt;&amp;gt; let addThree x y z = x + y + z;;   &lt;br /&gt;val addThree : int -&amp;gt; int -&amp;gt; int -&amp;gt; int    &lt;br /&gt;&amp;gt; let addTwo x y = addThree 10 x y;;    &lt;br /&gt;val addTwo : int -&amp;gt; int -&amp;gt; int    &lt;br /&gt;&amp;gt; addTwo 1 1;;    &lt;br /&gt;val it : int = 12&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;6. Union类型（Union Types，Discriminated Unions）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;考虑下面的枚举值：&lt;/p&gt;  &lt;p&gt;enum CardSuit { Spade = 1, Club = 2, Heart = 3, Diamond = 4};&lt;/p&gt;  &lt;p&gt;理论上，一个card实例只有一种可能的取值，但由于enum本质上只是整数，您不能确定它的值是否是有效的，在C#中，你可以这么写：&lt;/p&gt;  &lt;p&gt;CardSuit invalid1 = (CardSuit) 9000;   &lt;br /&gt;CardSuit invalid2 = CardSuit.Club | CardSuit.Diamond;&lt;/p&gt;  &lt;p&gt;另外，考虑下面的情形。如果您需要扩展一个enum：&lt;/p&gt;  &lt;p&gt;enum Title { Mr, Mrs }&lt;/p&gt;  &lt;p&gt;Title枚举可以工作地很好，但一段时间后，如果需要添加一个&amp;#8220;Ms&amp;#8221;值，那么每一个switch语句都面临一个潜在的bug。当然您可以尝试修复所有的代码，却难免会发生遗漏。&lt;/p&gt;  &lt;p&gt;枚举可以很好地表达某些概念，但是却无法提供足够的编译器检查。F#中的Union类型可设定为一组有限的值：数据标签（data tag）。例如，考虑一个表示微软员工的Union：&lt;/p&gt;  &lt;p&gt;type MicrosoftEmployee =   &lt;br /&gt;| BillGates    &lt;br /&gt;| SteveBalmer    &lt;br /&gt;| Worker of string    &lt;br /&gt;| Lead of string * MicrosoftEmployee list &lt;/p&gt;  &lt;p&gt;如果有一个MicrosoftEmployee类型的实例，您就知道它必定是{BillGates，SteveBalmer，Worker，Lead}之一。另外，如果它是Worker，您可以知道有一个字符串与之关联，也许是他的名字。我们可以轻松地创建Union类型，而后使用模式匹配（下一小节）来匹配它们的值。&lt;/p&gt;  &lt;p&gt;let myBoss = Lead(&amp;quot;Yasir&amp;quot;, [Worker(&amp;quot;Chris&amp;quot;); Worker(&amp;quot;Matteo&amp;quot;); Worker(&amp;quot;Santosh&amp;quot;)])   &lt;br /&gt;let printGreeting (emp : MicrosoftEmployee) =    &lt;br /&gt;match emp with    &lt;br /&gt;| BillGates&amp;#160;&amp;#160; -&amp;gt; printfn &amp;quot;Hello, Bill&amp;quot;    &lt;br /&gt;| SteveBalmer -&amp;gt; printfn &amp;quot;Hello, Steve&amp;quot;    &lt;br /&gt;| Worker(name) | Lead(name, _)    &lt;br /&gt;-&amp;gt; printfn &amp;quot;Hello, %s&amp;quot; name&lt;/p&gt;  &lt;p&gt;现在假设需要扩展Union类型：&lt;/p&gt;  &lt;p&gt;type MicrosoftEmployee =   &lt;br /&gt;| BillGates    &lt;br /&gt;| SteveBalmer    &lt;br /&gt;| Worker of string    &lt;br /&gt;| Lead&amp;#160;&amp;#160; of string * MicrosoftEmployee list    &lt;br /&gt;| ChrisSmith&lt;/p&gt;  &lt;p&gt;我们会看到一些编译器警告信息：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_12.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_5.png" width="562" height="104" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;编译器检测到您没有匹配Union的每一个数据标签，发出了警告。像这样的检查会避免很多bug，要了解&lt;/p&gt;  &lt;p&gt;更多的关于Union类型的信息，看&lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/04/18/a-java-to-x86-compiler-written-in-f.aspx"&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/04/18/a-java-to-x86-compiler-written-in-f.aspx"&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;7. 模式匹配（Pattern Matching）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;模式匹配看起来像是增强版的switch语句，允许您完成分支型控制流程。除了跟常数值进行比较外，还可以捕获新的值。比如在前面的例子中，我们在匹配Union数据标签时绑定了标识符&amp;#8220;name&amp;#8221;。&lt;/p&gt;  &lt;p&gt;let printGreeting (emp : MicrosoftEmployee) =   &lt;br /&gt;match emp with    &lt;br /&gt;| BillGates&amp;#160;&amp;#160; -&amp;gt; printfn &amp;quot;Hello, Bill&amp;quot;    &lt;br /&gt;| SteveBalmer -&amp;gt; printfn &amp;quot;Hello, Steve&amp;quot;    &lt;br /&gt;| Worker(name) | Lead(name, _)    &lt;br /&gt;-&amp;gt; printfn &amp;quot;Hello, %s&amp;quot; name &lt;/p&gt;  &lt;p&gt;还可以对数据的&amp;#8220;结构&amp;#8221;进行匹配，比如对列表（list）进行匹配。（还记得吗，x :: y表示x为列表的一个元素，y是x之后的元素，而[]则是空列表。） &lt;/p&gt;  &lt;p&gt;let listLength aList =   &lt;br /&gt;match aList with    &lt;br /&gt;| [] -&amp;gt; 0    &lt;br /&gt;| a :: [] -&amp;gt; 1    &lt;br /&gt;| a :: b :: [] -&amp;gt; 2    &lt;br /&gt;| a :: b :: c :: [] -&amp;gt; 3    &lt;br /&gt;| _ -&amp;gt; failwith &amp;quot;List is too big!&amp;quot;&lt;/p&gt;  &lt;p&gt;在这个匹配的最后，我们使用了通配符&amp;#8220;_&amp;#8221;（下划线），它匹配任意值。如果aList变量包含多于三个的元素，最后的模式子句将执行，并抛出一个异常。模式匹配还可以我们执行任意表达式来确定模式是否匹配（如果表达式的值为false，则不匹配）。 &lt;/p&gt;  &lt;p&gt;let isOdd x =   &lt;br /&gt;match x with    &lt;br /&gt;| _ when x % 2 = 0 -&amp;gt; false    &lt;br /&gt;| _ when x % 2 = 1 -&amp;gt; true&lt;/p&gt;  &lt;p&gt;我们甚至可以使用动态类型测试进行匹配：&lt;/p&gt;  &lt;p&gt;let getType (x : obj) =   &lt;br /&gt;match x with    &lt;br /&gt;| :? string -&amp;gt; &amp;quot;x is a string&amp;quot;    &lt;br /&gt;| :? int -&amp;gt; &amp;quot;x is a int&amp;quot;    &lt;br /&gt;| :? System.Exception -&amp;gt; &amp;quot;x is an exception&amp;quot;    &lt;br /&gt;| :? _ -&amp;gt; &amp;quot;invalid type&amp;quot;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;8. 记录类型（Records）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在声明包含若干个公有属性的类型时，记录类型是一种轻量级的方式。它的一个优势是，借助于类型推演系统，编译器可以通过值的声明得出适当的记录类型。&lt;/p&gt;  &lt;p&gt;type Address = {Name : string; Address : string; Zip : int}&lt;/p&gt;  &lt;p&gt;let whiteHouse = {Name = &amp;quot;The White House&amp;quot;; Address = &amp;quot;1600 Pennsylvania Avenue&amp;quot;;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Zip = 20500}&amp;#160; &lt;/p&gt;  &lt;p&gt;在上面的例子中，首先定义了&amp;#8220;Address&amp;#8221;类型，那么在声明它的实例时，无须显式地使用类型注解，编译器可根据字段（属性）的名称自行得出类型的信息。所以whiteHouse的类型为Address。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;9. Forward Pipe Operator（|&amp;gt;）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;|&amp;gt;操作符只是简单地定义为：&lt;/p&gt;  &lt;p&gt;let (|&amp;gt;) x f = f x&lt;/p&gt;  &lt;p&gt;其类型前面信息为：&lt;/p&gt;  &lt;p&gt;&amp;#39;a -&amp;gt; (&amp;#39;a -&amp;gt; &amp;#39;b) -&amp;gt; &amp;#39;b&lt;/p&gt;  &lt;p&gt;可以这么来理解：x的类型为&amp;#39;a，函数f接受&amp;#39;a类型的参数，返回类型为&amp;#39;b，操作符的结果就是将x传递给f后所求得的值。&lt;/p&gt;  &lt;p&gt;还是来看个例子吧：&lt;/p&gt;  &lt;p&gt;// Take a number, square it, then convert it to a string, then reverse that string   &lt;br /&gt;let square x&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = x * x    &lt;br /&gt;let toStr (x : int)&amp;#160; = x.ToString()    &lt;br /&gt;let rev&amp;#160;&amp;#160; (x : string) = new String(Array.rev (x.ToCharArray()))    &lt;br /&gt;// 32 -&amp;gt; 1024 -&amp;gt; &amp;quot;1024&amp;quot; -&amp;gt; &amp;quot;4201&amp;quot;    &lt;br /&gt;let result = rev (toStr (square 32))&lt;/p&gt;  &lt;p&gt;上面的代码是很直白的，但语法看起来却不太好。我们所做的就是将一个运算的结果传给下一个运算。我们可以通过引入几个变量来改写代码为：&lt;/p&gt;  &lt;p&gt;let step1 = square 32   &lt;br /&gt;let step2 = toStr step1    &lt;br /&gt;let step3 = rev step2    &lt;br /&gt;let result = step3&lt;/p&gt;  &lt;p&gt;但是我们需要维护这几个临时变量。|&amp;gt;操作符接受一个值，将其&amp;#8220;转交&amp;#8221;给一个函数。这会大大地简化F#代码：&lt;/p&gt;  &lt;p&gt;let result = 32 |&amp;gt; square |&amp;gt; toStr |&amp;gt; rev&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;10. 序列（Sequence，System.Collections.Generic.IEnumerator&amp;lt;_&amp;gt;）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;序列（在F#中为seq）是 System.Collections.Generic.IEnumerator的别名，但它在F#中有另外的作用。不像列表和数组，序列可包含无穷个值。只有当前的值保存在内存中，一旦序列计算了下个值，当前的值就会被忘记（丢弃）。例如，下面的代码生成了一个包含所有整数的序列。&lt;/p&gt;  &lt;p&gt;let allIntegers = Seq.init_infinite (fun i -&amp;gt; i)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;11. 集合（Collections：Seq，List，Array）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在F#中，如果您想表示一个值的集合，至少有三个好的选择&amp;#8212;&amp;#8212;数组、列表和序列，它们都有各自的优点。而且每种类型都有一系列的模块内置于F#库中。您可以使用VS的智能感知来探究这些方法，这里我们来看看最常用的那些：&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;iter&lt;/strong&gt;。&amp;#8220;iter&amp;#8221;函数遍历集合的每一项。这与&amp;#8220;foreach&amp;#8221;循环是一致的。下面的代码打印列表的每一项：&lt;/p&gt;  &lt;p&gt;List.iter (fun i -&amp;gt; printfn &amp;quot;Has element %d&amp;quot; i) [1 .. 10]&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;map&lt;/strong&gt;。像我在前面所说的，map函数基于一个指定的函数对集合的值进行转换。下面的例子将数组的整数值转换为它们的字符串表示：&lt;/p&gt;  &lt;p&gt;Array.map (fun (i : int) -&amp;gt; i.ToString()) [| 1 .. 10 |]&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;fold&lt;/strong&gt;。&amp;#8220;fold&amp;#8221;函数接受一个集合，并将集合的值折叠为单个的值。像iter和map一样，它接受一个函数，将其应用于集合的每个元素，但它还接受另一个&amp;#8220;accumulator&amp;#8221;参数。fold函数基于上一次运算不断地累积accumulator参数的值。看下面的例子：&lt;/p&gt;  &lt;p&gt;Seq.fold (fun acc i -&amp;gt; i + acc) 10 { 1 .. 10 }&lt;/p&gt;  &lt;p&gt;该代码的功能是：以10为基数（acculator），累加序列中的每一项。&lt;/p&gt;  &lt;p&gt;只有序列有fold方法，列表和数组则有fold_left和fold_right方法。它们的不同之处在于计算顺序的不同。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;12. 可选值（Option Values）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;基于函数式编程的特点，在F#中很难见到null值。但有些情况下，null值比未初始化变量更有意义。有时可选值则表示值未提供（可选值就像C#中的nullable类型）。&lt;/p&gt;  &lt;p&gt;F#中的&amp;#8220;可选类型（option type）&amp;#8221;有两种状态：&amp;#8220;Some&amp;#8221;和&amp;#8220;None&amp;#8221;。在下面的记录类型Person中，中间的字段可能有值，也可能没有值。&lt;/p&gt;  &lt;p&gt;type Person = { First : string; MI : string option; Last : string }   &lt;br /&gt;let billg&amp;#160;&amp;#160;&amp;#160; = {First = &amp;quot;Bill&amp;quot;;&amp;#160; MI = Some(&amp;quot;H&amp;quot;); Last = &amp;quot;Gates&amp;quot; }    &lt;br /&gt;let chrsmith = {First = &amp;quot;Chris&amp;quot;; MI = None;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Last = &amp;quot;Smith&amp;quot; } &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;13. 延迟求值（惰性值，Lazy Values，Microsoft.FSharp.Core.Lazy&amp;lt;_&amp;gt;）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;延迟初始化表示一些值，它们在需要时才进行计算。F#拥有延迟求值特性。看下面的例子，&amp;#8220;x&amp;#8221;是一个整数，当对其进行求值时会打印&amp;#8220;Computed&amp;#8221;。&lt;/p&gt;  &lt;p&gt;&amp;gt; let x = lazy (printfn &amp;quot;Computed.&amp;quot;; 42);;   &lt;br /&gt;val x : Lazy&amp;lt;int&amp;gt;    &lt;br /&gt;&amp;gt; let listOfX = [x; x; x];;    &lt;br /&gt;val listOfX : Lazy&amp;lt;int&amp;gt; list    &lt;br /&gt;&amp;gt; x.Force();;    &lt;br /&gt;Computed.    &lt;br /&gt;val it : int = 42&lt;/p&gt;  &lt;p&gt;可以看到，我们在调用&amp;#8220;Force&amp;#8221;方法时，对x进行求值，返回的值是42。您可以使用延迟初始化来避免不必要的计算。另外在构造递归值时，也很有用。例如，考虑一个Union值，它用来表示循环列表：&lt;/p&gt;  &lt;p&gt;type InfiniteList =   &lt;br /&gt;| ListNode of int * InfiniteList    &lt;br /&gt;let rec circularList = ListNode(1, circularList)&lt;/p&gt;  &lt;p&gt;&amp;#8220;circularList&amp;#8221;拥有对自身的引用（表示一个无限循环）。不使用延迟初始化的话，声明这样类型的值是不可能的。&lt;/p&gt;  &lt;p&gt;现在，您应该对F#的基础有了足够的了解了，下一步，在系列文章的第三部分中，我们将学习一些高级主题&amp;#8212;&amp;#8212;一些F#能做而其他的.NET语言不能做的事情，敬请期待！&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;接下来我们看看开发F#时可以选用的不同方式。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;（一）Notepad&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#程序本质上就是文本文件，所以我们可以使用文本编辑器来编写，比如记事本。它的文件扩展名为.fs，编写完毕后使用fsc.exe来编译。比如，编写一个最简单的文件helloworld.fs：&lt;/p&gt;  &lt;p&gt;#light   &lt;br /&gt;print_endline &amp;quot;Hello World&amp;quot;    &lt;br /&gt;read_line() &lt;/p&gt;  &lt;p&gt;使用命令fsc.exe helloworld.fs编译该文件，生成helloworld.exe文件，它将在控制台输出一段文本。注意要将fsc.exe的路径添加到环境变量中。&lt;/p&gt;  &lt;p&gt;如果采用文本编辑器的方式，我们当然不会真的使用Notepad，大可以采用Editplus或Notepad++这样的工具，它们不但提供了更强大的编辑功能，还可以添加用户自定义工具，这样就不用每次都打开命令行编译了。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;（二）FSI&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#交互控制台（F# Interactive Console, FSI）采用的是&amp;#8220;REPL loop&amp;#8221;模式，即Read-Evaluate-Print-Loop。也就是输入一段代码，编译并执行，然后输出结果。通过它您可以快速地开发和测试程序。可在开始菜单中找到它。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;（三）VFSI（在VS中集成FSI）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;要在VS中启用FSI，打开Add-in Manager窗口。 &lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_32.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_15.png" width="444" height="386" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;选中&amp;#8220;F# Inactive for Visual Studio&amp;#8221;。然后，选中要执行的程序代码： &lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_30.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_14.png" width="260" height="110" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;接着按下Alt+Enter（实际上，如果FSI还么有打开，需要按两次Alt+Enter）。这时会看到出现了一个工具窗口： &lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_28.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_13.png" width="496" height="405" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;我们刚才做的事情是将代码片段直接发送给FSI会话，FSI将结果输出。 &lt;/p&gt;  &lt;p&gt;这是最简单的方式了，我们可以利用&lt;strong&gt;VS提供的智能感知，可以查看各个标识符的类型等信息&lt;/strong&gt;，非常方便。 &lt;/p&gt;  &lt;p&gt;另外我们可以&lt;strong&gt;将fsc.exe添加到外部工具&lt;/strong&gt;中，为该命令分配快捷键。比如可以这样添加： &lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_26.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_12.png" width="385" height="361" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;然后分配快捷键： &lt;/p&gt;  &lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_24.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_11.png" width="545" height="311" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;有时FSI会莫名地不能编译通过，通过这样的方式可以方便的将单个文件编译为可执行文件，编译也不会有问题了。 &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;（四）F# Script&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;除了.fs，我们还可以将代码文件保存为.fsx，在资源管理器中右击该文件，会发现&amp;#8220;Run with F# Interactive&amp;#8221;菜单项，选择它就可以执行代码了，这种方式适合于小型文件，可以随时修改，无须编译。 &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;（五）SharpDevelop&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;最新版的SharpDevelop提供了对F#项目的支持，但是不支持智能感知。我觉得最有用的是它的文件顺序调整功能，如果你的项目包含较多的文件，可以试试它。 &lt;/p&gt;  &lt;p&gt;最后，建议主要使用第三种方式即VFSI开发，其它的作为补充。&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;函数式编程范式简介&lt;/strong&gt;    &lt;br /&gt;F#主要支持三种编程范式：函数式编程（Functional Programming，FP）、命令式编程（Imperative Programming）和面向对象（Object-Oriented，OO）的编程。回顾它们的历史，FP是最早的一种范式，第一种FP语言是IPL，产生于1955年，大约在Fortran一年之前。第二种FP语言是Lisp，产生于1958，早于Cobol一年。Fortan和Cobol都是命令式编程语言，它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟，至今已是最流行的编程范式。有道是&amp;#8220;江山代有语言出，各领风骚数十年&amp;#8221;。    &lt;br /&gt;尽管强大的FP语言（SML，Ocaml，Haskell及Clean等）和类FP语言（APL和Lisp是现实世界中最成功的两个）在1950年代就不断发展，FP仍停留在学院派的&amp;#8220;象牙塔&amp;#8221;里；而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天，FP的潜力终被认识&amp;#8212;&amp;#8212;它是用来解决更复杂的问题的（当然更简单的问题也不在话下）。    &lt;br /&gt;纯粹的FP将程序看作是接受参数并返回值的函数的集合，它不允许有副作用（side effect，即改变了状态），使用递归而不是循环进行迭代。FP中的函数很像数学中的函数，它们都不改变程序的状态。举个简单的例子，一旦将一个值赋给一个标识符，它就不会改变了，函数不改变参数的值，返回值是全新的值。    &lt;br /&gt;FP的数学基础使得它很是优雅，FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题，它的优势之一就是融合了多种编程范式，允许开发人员按照需要采用最好的范式。    &lt;br /&gt;关于FP的更多内容建议阅读一下这篇文章：&lt;a href="http://www.md.chalmers.se/%7Erjmh/Papers/whyfp.pdf"&gt;Why Functional Programming Matters&lt;/a&gt;（&lt;a href="http://www.nirvanastudio.org/wp-content/uploads/2006/08/why%20functional%20programming%20matters.html"&gt;中文版&lt;/a&gt;）。    &lt;br /&gt;&lt;strong&gt;F#中的函数式编程&lt;/strong&gt;    &lt;br /&gt;从现在开始，我将对F#中FP相关的主要语言结构逐一进行介绍。    &lt;br /&gt;&lt;strong&gt;标识符（Identifier）&lt;/strong&gt;    &lt;br /&gt;在F#中，我们通过标识符给值（value）取名字，这样就可以在后面的程序中引用它。通过关键字let定义标识符，如：&lt;/p&gt;  &lt;p&gt;let x = 42&lt;/p&gt;  &lt;p&gt;这看起来像命令式编程语言中的赋值语句，两者有着关键的不同。在纯粹的FP中，一旦值赋给了标识符就不能改变了，这也是把它称为标识符而非变量（variable）的原因。另外，在某些条件下，我们可以重定义标识符；在F#的命令式编程范式下，在某些条件下标识符的值是可以修改的。   &lt;br /&gt;标识符也可用于引用函数，在F#中函数本质上也是值。也就是说，F#中没有真正的函数名和参数名的概念，它们都是标识符。定义函数的方式与定义值是类似的，只是会有额外的标识符表示参数：&lt;/p&gt;  &lt;p&gt;let add x y = x + y&lt;/p&gt;  &lt;p&gt;这里共有三个标识符，add表示函数名，x和y表示它的参数。   &lt;br /&gt;&lt;strong&gt;关键字和保留字&lt;/strong&gt;    &lt;br /&gt;&lt;strong&gt;关键字&lt;/strong&gt;是指语言中一些标记，它们被编译器保留作特殊之用。在F#中，不能用作标识符或类型的名称（后面会讨论&amp;#8220;定义类型&amp;#8221;）。它们是：&lt;/p&gt;  &lt;p&gt;abstract and as asr assert begin class default delegate do done   &lt;br /&gt;downcast downto elif else end exception extern false finally for    &lt;br /&gt;fun function if in inherit inline interface internal land lazy let    &lt;br /&gt;lor lsr lxor match member mod module mutable namespace new null    &lt;br /&gt;of open or override private public rec return sig static struct    &lt;br /&gt;then to true try type upcast use val void when while with yield&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;保留字&lt;/strong&gt;是指当前还不是关键字，但被F#保留做将来之用。可以用它们来定义标识符或类型名称，但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性，最好不要使用。它们是：&lt;/p&gt;  &lt;p&gt;atomic break checked component const constraint constructor continue   &lt;br /&gt;eager event external fixed functor global include method mixin    &lt;br /&gt;object parallel process protected pure sealed trait virtual volatile&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;文字值（Literals）&lt;/strong&gt;    &lt;br /&gt;文字值表示常数值，在构建计算代码块时很有用，F#提供了丰富的文字值集。与C#类似，这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等，在此不再赘述，详细信息请查看&lt;a href="http://research.microsoft.com/fsharp/manual/spec2.aspx"&gt;F#手册&lt;/a&gt;。    &lt;br /&gt;与C#一样，F#中的字符串常量表示也有两种方式。一是常规字符串（regular string），其中可包含转义字符；二是逐字字符串（verbatim string），其中的（&amp;quot;）被看作是常规的字符，而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示：&lt;/p&gt;  &lt;p&gt;let message = &amp;quot;Hello World&amp;quot;r&amp;quot;n!&amp;quot; // 常规字符串   &lt;br /&gt;let dir = @&amp;quot;C:&amp;quot;FS&amp;quot;FP&amp;quot; // 逐字字符串    &lt;br /&gt;let bytes = &amp;quot;bytes&amp;quot;B // byte 数组    &lt;br /&gt;let xA = 0xFFy&amp;#160; // sbyte, 16进制表示    &lt;br /&gt;let xB = 0o777un // unsigned native-sized integer，8进制表示    &lt;br /&gt;let print x = printfn &amp;quot;%A&amp;quot; x    &lt;br /&gt;let main() =    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print message;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print dir;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print bytes;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print xA;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print xB;    &lt;br /&gt;main()&lt;/p&gt;  &lt;p&gt;Printf函数通过F#的反射机制和.NET的ToString方法来解析&amp;#8220;%A&amp;#8221;模式，适用于任何类型的值，也可以通过F#中的print_any和print_to_string函数来完成类似的功能。   &lt;br /&gt;&lt;strong&gt;值和函数（Values and Functions）&lt;/strong&gt;    &lt;br /&gt;在F#中函数也是值，F#处理它们的语法也是类似的。&lt;/p&gt;  &lt;p&gt;let n = 10   &lt;br /&gt;let add a b = a + b    &lt;br /&gt;let addFour = add 4    &lt;br /&gt;let result = addFour n    &lt;br /&gt;printfn &amp;quot;result = %i&amp;quot; result&lt;/p&gt;  &lt;p&gt;可以看到定义值n和函数add的语法很类似，只不过add还有两个参数。对于add来说a + b的值自动作为其返回值，也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说，它定义在add的基础上，它只向add传递了一个参数，这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念，F(x, y) = x + y，G(y) = F(4, y)，实际上G(y) = 4 + y，G也是一个函数，它接收一个参数，这个地方是不是很类似？这种只向函数传递部分参数的特性称为函数的柯里化（curried function）。   &lt;br /&gt;当然对某些函数来说，传递部分参数是无意义的，此时需要强制提供所有参数，可是将参数括起来，将它们转换为元组（tuple）。下面的例子将不能编译通过：&lt;/p&gt;  &lt;p&gt;let sub(a, b) = a - b   &lt;br /&gt;let subFour = sub 4&lt;/p&gt;  &lt;p&gt;必须为sub提供两个参数，如sub(4, 5)，这样就很像C#中的方法调用了。   &lt;br /&gt;对于这两种方式来说，前者具有更高的灵活性，一般可优先考虑。    &lt;br /&gt;如果函数的计算过程中需要定义一些中间值，我们应当将这些行进行缩进：&lt;/p&gt;  &lt;p&gt;let halfWay a b =   &lt;br /&gt;let dif = b - a    &lt;br /&gt;let mid = dif / 2    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; mid + a&lt;/p&gt;  &lt;p&gt;需要注意的是，缩进时要用空格而不是Tab，如果你不想每次都按几次空格键，可以在&lt;strong&gt;VS中设置，将Tab字符自动转换为空格&lt;/strong&gt;；虽然缩进的字符数没有限制，但一般建议用4个空格。而且此时一定要用&lt;strong&gt;在文件开头添加#light指令&lt;/strong&gt;。    &lt;br /&gt;&lt;strong&gt;作用域（Scope）&lt;/strong&gt;    &lt;br /&gt;&lt;strong&gt;作用域&lt;/strong&gt;是编程语言中的一个重要的概念，它表示在何处可以访问（使用）一个标识符或类型。所有标识符，不管是函数还是值，其作用域都从其声明处开始，结束自其所处的代码块。对于一个处于最顶层的标识符而言，一旦为其赋值，它的值就不能修改或重定义了。标识符在定义之后才能使用，这意味着在定义过程中不能使用自身的值。&lt;/p&gt;  &lt;p&gt;let defineMessage() =   &lt;br /&gt;let message = &amp;quot;Help me&amp;quot;    &lt;br /&gt;print_endline message // error &lt;/p&gt;  &lt;p&gt;对于在函数内部定义的标识符，一般而言，它们的作用域会到函数的结束处。   &lt;br /&gt;但可使用let关键字重定义它们，有时这会很有用，对于某些函数来说，计算过程涉及多个中间值，因为值是不可修改的，所以我们就需要定义多个标识符，这就要求我们去维护这些标识符的名称，其实是没必要的，这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型，但F#仍能确保类型安全。所谓类型安全，其基本意义是F#会避免对值的错误操作，比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。&lt;/p&gt;  &lt;p&gt;let changeType() =   &lt;br /&gt;let x = 1    &lt;br /&gt;let x = &amp;quot;change me&amp;quot;    &lt;br /&gt;let x = x + 1    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print_string x&lt;/p&gt;  &lt;p&gt;在本例的函数中，第一行和第二行都没问题，第三行就有问题了，在重定义x的时候，赋给它的值是x + 1，而x是字符串，与1相加在F#中是非法的。   &lt;br /&gt;另外，如果在嵌套函数中重定义标识符就更有趣了。&lt;/p&gt;  &lt;p&gt;let printMessages() =   &lt;br /&gt;let message = &amp;quot;fun value&amp;quot;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; printfn &amp;quot;%s&amp;quot; message;    &lt;br /&gt;let innerFun () =    &lt;br /&gt;let message = &amp;quot;inner fun value&amp;quot;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; printfn &amp;quot;%s&amp;quot; message    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; innerFun ()    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; printfn &amp;quot;%s&amp;quot; message    &lt;br /&gt;printMessages()&lt;/p&gt;  &lt;p&gt;打印结果：&lt;/p&gt;  &lt;p&gt;fun value   &lt;br /&gt;inner fun value    &lt;br /&gt;fun value&lt;/p&gt;  &lt;p&gt;最后一次不是inner fun value，因为在innerFun仅仅将值重新绑定而不是赋值，其有效范围仅仅在innerFun内部。   &lt;br /&gt;&lt;strong&gt;递归（Recursion）&lt;/strong&gt;    &lt;br /&gt;&lt;strong&gt;递归&lt;/strong&gt;是编程中的一个极为重要的概念，它表示函数通过自身进行定义，亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。    &lt;br /&gt;使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数：&lt;/p&gt;  &lt;p&gt;let rec factorial x =   &lt;br /&gt;match x with    &lt;br /&gt;| x when x &amp;lt; 0 -&amp;gt; failwith &amp;quot;value must be greater than or equal to 0&amp;quot;    &lt;br /&gt;| 0 -&amp;gt; 1    &lt;br /&gt;| x -&amp;gt; x * factorial(x - 1)&lt;/p&gt;  &lt;p&gt;这里使用了模式匹配（F#的一个很棒的特性），其C#版本为：&lt;/p&gt;  &lt;p&gt;public static long Factorial(int n)   &lt;br /&gt;{    &lt;br /&gt;if (n &amp;lt; 0) { throw new ArgumentOutOfRangeException(&amp;quot;value must be greater than or equal to 0&amp;quot;); }    &lt;br /&gt;if (n == 0) { return 1; }    &lt;br /&gt;return n * Factorial (n - 1);    &lt;br /&gt;}&lt;/p&gt;  &lt;p&gt;递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心，可能会写出不能终止的递归。   &lt;br /&gt;&lt;strong&gt;匿名函数（Anonymous Function）&lt;/strong&gt;    &lt;br /&gt;定义函数的时候F#提供了第二种方式：使用关键字fun。有时我们没必要给函数起名，这种函数就是所谓的匿名函数，有时称为lambda函数，这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数，通常就不需要起名。在后面的&amp;#8220;列表&amp;#8221;一节中你会看到这样的例子。除了fun，我们还可以使用function关键字定义匿名函数，它们的区别在于后者可以使用模式匹配（本文后面将做介绍）特性。看下面的例子：&lt;/p&gt;  &lt;p&gt;let x = (fun x y -&amp;gt; x + y) 1 2   &lt;br /&gt;let x1 = (function x -&amp;gt; function y -&amp;gt; x + y) 1 2    &lt;br /&gt;let x2 = (function (x, y) -&amp;gt; x + y) (1, 2)&lt;/p&gt;  &lt;p&gt;我们可优先考虑fun，因为它更为紧凑，在F#类库中你能看到很多这样的例子。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：本文中的代码均在F# 1.9.4.17版本下编写，在F# CTP 1.9.6.0版本下可能不能通过编译。 &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;操作符（Operator） &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;F#中，可把操作符看作一种函数调用的更为优雅的方式。操作符有两种：前缀（prefix）和中缀（infix），前者接受一个操作数（operand），出现在操作数之前；后者接受两个或多个操作数，出现在头两个操作数之间。 &lt;/p&gt;  &lt;p&gt;F#提供了丰富的操作符集，可用于数字、布尔值、字符串和集合类型。这些操作符数量甚众，限于篇幅，在此不再一一详解。本文将着重介绍如何使用和定义操作符。   &lt;br /&gt;类似于C#，F#的操作符也可以重载，也就是说，我们可以将不同的类型用于同一操作符，如&amp;#8220;+&amp;#8221;；但是与C#不同的是，各个操作数必须为相同的类型。F#的操作符重载规则与C#类似，因此任何BCL或者使用C#编写的.NET类库中的支持操作符重载的类在F#中一样支持重载。&lt;/p&gt;  &lt;p&gt;let words = &amp;quot;To live &amp;quot; + &amp;quot;is &amp;quot; + &amp;quot; to function.&amp;quot;   &lt;br /&gt;open System    &lt;br /&gt;let oneYearLater = DateTime.Now + new TimeSpan(365, 0, 0, 0, 0) &lt;/p&gt;  &lt;p&gt;我们可以定义自己的操作符，也可以重定义已有的任何操作符（不建议这样做）。看看下面这种不好的做法：&lt;/p&gt;  &lt;p&gt;let (+) a b = a &amp;#8211; b   &lt;br /&gt;print_int (1 + 2)&lt;/p&gt;  &lt;p&gt;看到这里，你想到了什么？是不是：这分明是在定义一个函数嘛！所以我们前面说&amp;#8220;可把操作符看作一种函数调用的更为优雅的方式&amp;#8221;。我们重定义了&amp;#8220;+&amp;#8221;操作符，所以&amp;#8220;1 + 2&amp;#8221;的结果为-1，这当然没什么好处，在VS中使用FSI时，怎样把&amp;#8220;+&amp;#8221;改回它原本的含义呢？我一般在任务管理器中把fsi进程关掉，再按回车，&amp;#8220;+&amp;#8221;就回来了。   &lt;br /&gt;自定义的操作符不能包含字母和数字，可以使用的字符如下：    &lt;br /&gt;!$%&amp;amp;+-./&amp;lt;=&amp;gt;?@^|~    &lt;br /&gt;:    &lt;br /&gt;操作符的第一个字符可以是上面第一行的任意字符，其后的字符则可以是上面的任意字符了。定义语法与函数类似，除了要将操作括起来。看下面的例子：&lt;/p&gt;  &lt;p&gt;let (+^*) a b = (a + b) * (a * b) &lt;/p&gt;  &lt;p&gt;结果为30。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;列表（Lists）&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;列表是内置于F#的简单集合类型。可以是一个空表（empty list），使用方括号表示（[]）。我们可以将一个值与列表连接，此时要使用&amp;#8220;::&amp;#8221;操作符，注意要将值作为第一个操作数：&lt;/p&gt;  &lt;p&gt;let emptyList = []   &lt;br /&gt;let oneItem = &amp;quot;one&amp;quot; :: []    &lt;br /&gt;let twoItem = &amp;quot;two&amp;quot; :: oneItem&lt;/p&gt;  &lt;p&gt;在VS中可以看到oneItem的类型为string list。如果列表包含多个项，用上面的方法显得麻烦了，我们可以使用下面的语法：&lt;/p&gt;  &lt;p&gt;let shortHand = [&amp;quot;hello &amp;quot;; &amp;quot;world!&amp;quot;]&lt;/p&gt;  &lt;p&gt;另外我们还可使用&amp;#8220;@&amp;#8221;操作符来连接两个列表：&lt;/p&gt;  &lt;p&gt;let concatenateLists = [&amp;quot;one, &amp;quot;; &amp;quot;two, &amp;quot;] @ [&amp;quot;three, &amp;quot;; &amp;quot;four&amp;quot;]&lt;/p&gt;  &lt;p&gt;F#要求列表中的元素类型必须是相同的，如果你确实需要列表包含不同类型的元素，那只好创建一个obj（即System.Object）类型的列表了：&lt;/p&gt;  &lt;p&gt;let objList = [box 1; box 2.0; box &amp;quot;three&amp;quot;]&lt;/p&gt;  &lt;p&gt;其中第三个box是可选的，这个让我想起了C#中的装箱。   &lt;br /&gt;F#中的列表是不可修改的，一旦创建就不能修改了。作用于列表的函数和操作符也不能修改列表，而是创建了列表的一个副本。这个特性很像C#中的string类型。看下面的例子：&lt;/p&gt;  &lt;p&gt;#light   &lt;br /&gt;let printList list =    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; List.iter print_string list    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; print_newline()    &lt;br /&gt;let threeItems = [&amp;quot;one &amp;quot;; &amp;quot;two &amp;quot;; &amp;quot;three &amp;quot;]    &lt;br /&gt;let reversedList = List.rev threeItems    &lt;br /&gt;printList threeItems    &lt;br /&gt;printList reversedList&lt;/p&gt;  &lt;p&gt;上面的iter方法接受两个参数，第一个是函数，第二个是列表，其作用是将函数依次应用于列表的每个元素，有点像C#中的foreach循环。而rev方法则返回列表的逆序列表。&lt;/p&gt;  &lt;p&gt;打印结果为：   &lt;br /&gt;one tow three    &lt;br /&gt;three two one    &lt;br /&gt;上述两个方法都没有改变原来的列表。要了解关于F#列表的更多信息，建议阅读这篇文章：&lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/07/10/mastering-f-lists.aspx"&gt;Mastering F# Lists&lt;/a&gt;。    &lt;br /&gt;&lt;strong&gt;列表推导（List Comprehensions）&lt;/strong&gt;    &lt;br /&gt;列表推导的概念源于数学，它使得创建和转换集合的操作变得简单。在F#中可以使用这样的推导语法直接创建列表，序列（sequence）和数组（序列和数组将在后面介绍）。要了解这个概念的更多内容可以查看：&lt;a href="http://en.wikipedia.org/wiki/List_comprehension"&gt;List_comprehension&lt;/a&gt;。    &lt;br /&gt;最简单的情况是指定列表的范围，如：&lt;/p&gt;  &lt;p&gt;let numericList = [0 .. 9]   &lt;br /&gt;let charList = [&amp;#39;A&amp;#39; .. &amp;#39;Z&amp;#39;]&lt;/p&gt;  &lt;p&gt;这两个列表的类型分别是int list和char list，范围分别是从0到9和从&amp;#8217;A&amp;#8217;到&amp;#8217;Z&amp;#8217;。   &lt;br /&gt;更复杂的情况是指定一个步长：&lt;/p&gt;  &lt;p&gt;let multipleOfThree = [0 .. 3 .. 30]   &lt;br /&gt;let revNumericList = [9.. -1 .. 0]&lt;/p&gt;  &lt;p&gt;第一个列表的值是0到30间所有3的倍数，第二个列表的元素则包含了从9递减至0。   &lt;br /&gt;我们还可以通过对一个列表进行循环操作得到另一个列表。例如：&lt;/p&gt;  &lt;p&gt;let squares = [for x in 1 .. 10 -&amp;gt; x * x]&lt;/p&gt;  &lt;p&gt;通过for进行循环，squares列表的元素是1到10间的整数的平方。   &lt;br /&gt;此外还可以为循环添加when子句对元素进行过滤，只有when子句的值为true时才对其进行运算：&lt;/p&gt;  &lt;p&gt;let evens = [for x in 1 .. 10 when x % 2 = 0 -&amp;gt; x]&lt;/p&gt;  &lt;p&gt;evens的元素为[2; 4; 6; 8; 10]。   &lt;br /&gt;&lt;strong&gt;控制流程（Control Flow）&lt;/strong&gt;    &lt;br /&gt;F#拥有强的控制流程概念，这与很多纯函数式编程语言不同，在这些语言中表达式可以以任何顺序进行求值。看下面的例子：&lt;/p&gt;  &lt;p&gt;let absoluteValue x =   &lt;br /&gt;if x &amp;lt; 0 then    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; -x    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; elif x = 0 then    &lt;br /&gt;0    &lt;br /&gt;else    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; x&lt;/p&gt;  &lt;p&gt;if, elif, then, else组成的结构我们应当很熟悉，在F#中该结构是一个表达式，也就是说它需要返回一个值。而且每个分支返回的值应当具有相同的类型，否则就会有编译错误。如果确实要返回多个类型的值，在值前加box关键字，就像前面创建列表时那样，这样表达式的返回类型为obj。   &lt;br /&gt;&lt;strong&gt;类型与类型推导（Types and Type Inference）&lt;/strong&gt;    &lt;br /&gt;F#是一种&lt;strong&gt;强类型&lt;/strong&gt;的语言，传给函数的值必须是指定的类型。如果函数接受string类型的参数，就不能传给它int类型的值。一种语言处理其中值的类型的方式称为语言的类型系统。F#的类型系统与一般语言不同，包括函数在内，所有的值都具有自己的类型。    &lt;br /&gt;通常情况下，我们不需要显式地声明类型，编译器会尝试从值的文字值或调用的函数返回类型来判断其类型，这个过程称为&lt;strong&gt;类型推导&lt;/strong&gt;。可在编译时使用-i开关来显示所有的推导类型，在VS中我们则可以使用工具提示来查看标识符的类型。先看下面值的类型推导情况：&lt;/p&gt;  &lt;p&gt;let strValue = &amp;quot;String Value&amp;quot;   &lt;br /&gt;let intValue = 12&lt;/p&gt;  &lt;p&gt;在fsi中可看到它们的信息是：&lt;/p&gt;  &lt;p&gt;val strValue : string   &lt;br /&gt;val intValue : int&lt;/p&gt;  &lt;p&gt;可以理解，编译器跟据赋给标识符的文字值来推导其类型。再看看下面函数的情况：&lt;/p&gt;  &lt;p&gt;let makeMessage x = (string_of_bool x) + &amp;quot; is a boolean value&amp;quot;   &lt;br /&gt;let half x = x / 2&lt;/p&gt;  &lt;p&gt;在fsi中可看到它们的信息是：&lt;/p&gt;  &lt;p&gt;val makeMessage : bool -&amp;gt; string   &lt;br /&gt;val half : int -&amp;gt; int&lt;/p&gt;  &lt;p&gt;有意思的是，函数名前面也有个val，这表明函数也是值，后面的bool -&amp;gt; string是什么意思呢？它表明函数接受bool类型参数，返回string类型的值，注意x作为string_of_bool的参数，所以x必须为bool类型，返回值是两个字符串相加的值，故返回值也是string类型。对于half函数，单从定义不能确定x类型，此时编译器采用默认的类型int。再看看稍微复杂点的情况：&lt;/p&gt;  &lt;p&gt;let div1 x y = x / y   &lt;br /&gt;let div2 (x, y) = x / y&lt;/p&gt;  &lt;p&gt;这两个函数的信息是：&lt;/p&gt;  &lt;p&gt;val div1 : int -&amp;gt; int -&amp;gt; int   &lt;br /&gt;val div2 : int * int -&amp;gt; int&lt;/p&gt;  &lt;p&gt;div1函数可接受部分参数（可柯里化），而div2则必须同时传入两个int类型的值。考虑下面的函数：&lt;/p&gt;  &lt;p&gt;let doNothing x = x&lt;/p&gt;  &lt;p&gt;其信息为：&lt;/p&gt;  &lt;p&gt;val doNothing : &amp;#39;a -&amp;gt; &amp;#39;a&lt;/p&gt;  &lt;p&gt;a&amp;#8217; -&amp;gt; a&amp;#8217;表示函数接受任意类型，并返回与其相同类型的值。以&amp;#8217;打头的类型表示&lt;strong&gt;可变类型&lt;/strong&gt;（variable type），编译器虽然不能确定类型的参数，却能确定返回值类型必须与参数类型相同，类型系统的这种特性称为&lt;strong&gt;类型参数化&lt;/strong&gt;，通过它编译器也能发现更多的类型错误。可变类型或类型参数化的概念，类似于.NET 2.0的泛型，如果F#基于支持泛型的CLI，那么它会充分利用泛型的优势。另外，F#的创建者Don Syme，正是CLR中泛型的设计者和实现者。    &lt;br /&gt;F#的类型推导固然强大，但它显然不能揣测出开发人员所有的心思来，如果有特殊需求该怎么办呢？看下面的例子：&lt;/p&gt;  &lt;p&gt;let doNothingToFloat (x : float32) = x&lt;/p&gt;  &lt;p&gt;float32即System.Single，这里我们手动指定了x的类型，这个有时称为类型标注（type annotation）。如果要在F#中使用其它.NET语言编写的类库，或者与非托管的类库进行互操作，它会很有用。 &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;小结&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;本文继续介绍F#中的函数式编程范式，主要包含了操作符、列表、列表推导、类型推导、类型标注等概念。类型推导又称隐式类型，通常是&amp;#8212;&amp;#8212;但不限于&amp;#8212;&amp;#8212;函数式编程语言的特性，比如C# 3.0和VB.NET 9.0都提供了一定的支持，它使很多编程任务变得更为简单。 &lt;/p&gt;  &lt;p&gt;参考：   &lt;br /&gt;《Foundations of F#》 by Robert Pickering    &lt;br /&gt;《&lt;a href="http://research.microsoft.com/fsharp/manual/spec2.aspx"&gt;F# Specs&lt;/a&gt;》&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;模式匹配（Pattern Matching）&lt;/strong&gt;    &lt;br /&gt;&lt;strong&gt;     &lt;br /&gt;模式匹配允许你根据标识符值的不同进行不同的运算&lt;/strong&gt;。有点像一连串的if...else结构，也像C++和C#中的switch，但是它更为强大和灵活。    &lt;br /&gt;看下面Lucas序列的例子，Lucas序列定义跟Fibonacci序列一样，只不过起始值不同：&lt;/p&gt;  &lt;pre&gt;&lt;br /&gt;let rec luc x =&lt;br /&gt;    match x with&lt;br /&gt;    | x when x &amp;lt;= 0 -&amp;gt; failwith &amp;quot;value must be greater than zero&amp;quot;&lt;br /&gt;    | 1 -&amp;gt; 1&lt;br /&gt;    | 2 -&amp;gt; 3&lt;br /&gt;    | x -&amp;gt; luc(x - 1) + luc(x - 2)&lt;br /&gt;  &lt;br /&gt;printfn &amp;quot;(luc 2) = %i&amp;quot; (luc 2)&lt;br /&gt;printfn &amp;quot;(luc 6) = %i&amp;quot; (luc 6)&lt;/pre&gt;

&lt;p&gt;这里可以看到模式匹配的简单应用，使用关键字match和with，不同的模式规则间用&amp;#8220;|&amp;#8221;隔开，而&amp;#8220;-&amp;gt;&amp;#8221;表示如果该模式匹配，运算结果是什么。
  &lt;br /&gt;这个例子的打印结果为：&lt;/p&gt;

&lt;pre&gt;Output&lt;br /&gt;(luc 2) = 3&lt;br /&gt;(luc 6) = 18 &lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;匹配规则时按照它们定义的顺序，而且模式匹配必须完整定义，也就是说，对于任意一个可能的输入值，都有至少一个模式能够满足它&lt;/strong&gt;（即能处理它）；否则编译器会报告一个错误信息。另外，排在前面的规则不应比后面的更为&amp;#8220;一般&amp;#8221;，否则后面的规则永远不会得到匹配，编译器会报告一个警告信息，这种方式很像C#中的异常处理方式，在捕获异常时，我们不能先不会&amp;#8220;一般&amp;#8221;的Exception异常，然后再捕获&amp;#8220;更具体&amp;#8221;的NullReferenceException异常。&lt;/p&gt;

&lt;p&gt;可以为某个模式规则添加一个when卫语句（guard），可将when语句理解为对当前规则的更强的约束，只有when语句的值为true时，该模式规则才算匹配。在上例的第一个规则中，如果没有when语句，那么任意整数都能够匹配模式，加了when语句后，就只能匹配非正整数了。对于最简单的情况，我们可以省略第一个&amp;#8220;|&amp;#8221;：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let boolToString x =&lt;br /&gt;    match x with false -&amp;gt; &amp;quot;False&amp;quot; | _ -&amp;gt; &amp;quot;True&amp;quot;&lt;/pre&gt;

&lt;p&gt;这个例子中包含两个模式规则，&amp;#8220;_&amp;#8221;可以匹配任意值，因此当x值为false时匹配第一个规则，否则就匹配第二个规则。&lt;/p&gt;

&lt;p&gt;另一个有用的特性是，我们可以合并两个模式规则，对它们采取相同的处理方式，这个就像C#中的switch&amp;#8230;case结构中可以合并两个case一样。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let stringToBool x =&lt;br /&gt;    match x with&lt;br /&gt;    | &amp;quot;T&amp;quot; | &amp;quot;True&amp;quot; | &amp;quot;true&amp;quot; -&amp;gt; true&lt;br /&gt;    | &amp;quot;F&amp;quot; | &amp;quot;False&amp;quot; | &amp;quot;false&amp;quot; -&amp;gt; false&lt;br /&gt;    | _ -&amp;gt; failwith &amp;quot;Invalid input.&amp;quot;&lt;/pre&gt;

&lt;p&gt;在本例中，我们把三种模式规则合并在了一起，将字符串值转换为相应的布尔值。
  &lt;br /&gt;可以对大多数F#中定义的类型进行模式匹配，下面的例子就展示了对元组进行匹配。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let myOr b1 b2 =&lt;br /&gt;    match b1, b2 with&lt;br /&gt;    | true, _ -&amp;gt; true&lt;br /&gt;    | _, true -&amp;gt; true&lt;br /&gt;    | _ -&amp;gt; false&lt;br /&gt;   &lt;br /&gt;let myAnd p =&lt;br /&gt;    match p with&lt;br /&gt;    | true, true -&amp;gt; true&lt;br /&gt;    | _ -&amp;gt; false&lt;/pre&gt;

&lt;p&gt;这两个函数说明了如何对元组应用模式匹配，它们的功能是求两个布尔值&amp;#8220;或&amp;#8221;和&amp;#8220;且&amp;#8221;运算的结果。在myOr中，从第一、二两个模式规则可以知道b1、b2只要有一个为true，计算结果就是true，否则为false。myOr true false的结果为true，myAnd(true, false)结果为false。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;模式匹配的常见用法是对列表进行匹配&lt;/strong&gt;，事实上，对列表来说，较之if&amp;#8230;then&amp;#8230;else结构，模式匹配的方式更好。看下面的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let listOfList = [[2; 3; 5]; [7; 11; 13]; [17; 19; 23; 29]]&lt;br /&gt;&lt;br /&gt;let rec concatenateList list =&lt;br /&gt;    match list with&lt;br /&gt;    | head :: tail -&amp;gt; head @ (concatenateList tail)&lt;br /&gt;    | [] -&amp;gt; []&lt;br /&gt;   &lt;br /&gt;let rec concatenateList2 list =&lt;br /&gt;    if List.nonempty list then&lt;br /&gt;        let head = List.hd list in&lt;br /&gt;        let tail = List.tl list in&lt;br /&gt;        head @ (concatenateList2 tail)&lt;br /&gt;    else&lt;br /&gt;        []&lt;br /&gt;       &lt;br /&gt;let primes = concatenateList listOfList&lt;br /&gt;print_any primes&lt;/pre&gt;

&lt;p&gt;listOfList是一个列表的列表，两个函数concatenateList和concatenateList2的功能都是将listOfList的元素连接为一个大的列表，只不过一个用模式匹配方式实现，一个使用if&amp;#8230;then&amp;#8230;else结构实现。可以看到&lt;strong&gt;使用模式匹配的代码更为简洁明了&lt;/strong&gt;。观察concatenateList函数，它处理列表的方式是&lt;strong&gt;先取出列表的头元素（head），处理它，然后递归地处理剩余元素&lt;/strong&gt;，这其实是通过模式匹配方式处理列表的最常见的方式（但不是唯一的方式）。

  &lt;br /&gt;在F#中，模式匹配还可用在其它地方，在后面的文章中将陆续介绍。

  &lt;br /&gt;&lt;strong&gt;定义类型（Defining Types） &lt;/strong&gt;

  &lt;br /&gt;F#的类型系统提供了若干特性，可用来创建自定义类型。所有的类型可分为两类，一是&lt;strong&gt;元组&lt;/strong&gt;（Tuple）或&lt;strong&gt;记录&lt;/strong&gt;（Record），它们类似于C#中的类；二是&lt;strong&gt;Union类型&lt;/strong&gt;，有时称为&lt;strong&gt;Sum类型&lt;/strong&gt;。下面分别来看一下它们的特点。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;元组是任意对象的有序集合&lt;/strong&gt;，通过它我们可以快速、方便地将一组值组合在一起。创建之后，就可以引用元组中的值。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let pair = true, false&lt;br /&gt;let b1, b2 = pair&lt;br /&gt;let _, b3 = pair&lt;br /&gt;let b4, _ = pair&lt;/pre&gt;

&lt;p&gt;第一行代码创建了一个元组，其类型为bool * bool, 说明pair元组包含两个值，它们的类型都是bool。通过第二、三、四行这样的代码，可以访问元组的值，&amp;#8220;_&amp;#8221;告诉编译器，我们对该值不感兴趣，将其忽略。这里b1的值为true，b3的值为false。&lt;/p&gt;

&lt;p&gt;进一步分析，元组是一种类型，但是我们并没有显式地使用type关键字来声明类型，pair本质上是F#中Tuple类的一个实例，而不是自定义类型。&lt;strong&gt;如果需要声明自定义类型，就要使用type关键字&lt;/strong&gt;了，最简单的情况是给已有类型起个别名：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type Name = string&lt;br /&gt;// FirstName, LastName&lt;br /&gt;type FullName = string * string&lt;/pre&gt;

&lt;p&gt;对于Name类型来说，它仅仅是string类型的别名，FullName则是元组类型的别名。&lt;/p&gt;

&lt;p&gt;记录（Record）类型与元组有相似之处，它也是将多个类型的值组合为同一类型，不同之处在于&lt;strong&gt;记录类型中的字段都是有名称的&lt;/strong&gt;。看下面的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type Organization = { Boss : string; Lackeys : string list }&lt;br /&gt;&lt;br /&gt;let family =&lt;br /&gt;    { Boss = &amp;quot;Children&amp;quot;;&lt;br /&gt;     Lackeys = [&amp;quot;Wife&amp;quot;; &amp;quot;Husband&amp;quot;] }&lt;/pre&gt;

&lt;p&gt;第一行是创建Organization类型，第二行则是创建它的实例，令人惊奇的是不需要声明实例的类型，F#编译器能够根据字段名推导出它的类型。这个功能是很强大，但是F#不强求每个类型的字段都是不同的，如果两个类型的各个字段名都一样怎么办呢？这时可以显式地声明类型：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type Company = { Boss : string; Lackeys : string list }&lt;br /&gt;&lt;br /&gt;let myCom =&lt;br /&gt;    { new Company&lt;br /&gt;      with Boss = &amp;quot;Bill&amp;quot;&lt;br /&gt;      and Lackeys = [&amp;quot;Emp1&amp;quot;; &amp;quot;Emp2&amp;quot;] }&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;一般情况下，类型的作用域从声明处至所在源文件的结束&lt;/strong&gt;。如果一个类型要使用在它后面声明的类型，可将这两个类型声明在同一个代码块中。类型间用and分隔，看下面食谱的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type recipe =&lt;br /&gt;    { recipeName : string;&lt;br /&gt;      ingredients : ingredient list;&lt;br /&gt;      instructions : string }&lt;br /&gt;and ingredient =&lt;br /&gt;    { ingredientName : string;&lt;br /&gt;      quantity : int }&lt;br /&gt;&lt;br /&gt;let greenBeansPineNuts =&lt;br /&gt;    { recipeName = &amp;quot;Green Beans &amp;amp; Pine Nuts&amp;quot;;&lt;br /&gt;      ingredients =&lt;br /&gt;        [{ingredientName = &amp;quot;Green beans&amp;quot;; quantity = 200};&lt;br /&gt;         {ingredientName = &amp;quot;Pine nuts&amp;quot;; quantity = 200}];&lt;br /&gt;      instructions = &amp;quot;Parboil the green beans for about 7 minutes.&amp;quot; }&lt;br /&gt;     &lt;br /&gt;let name = greenBeansPineNuts.recipeName&lt;br /&gt;let toBuy =&lt;br /&gt;    List.fold_left&lt;br /&gt;        (fun acc x -&amp;gt;&lt;br /&gt;            acc + (Printf.sprintf &amp;quot;\t%s - %i\r\n&amp;quot; x.ingredientName x.quantity))&lt;br /&gt;        &amp;quot;&amp;quot; greenBeansPineNuts.ingredients&lt;br /&gt;let instructions = greenBeansPineNuts.instructions&lt;br /&gt;&lt;br /&gt;printf &amp;quot;%s\r\n%s\r\n\r\n\t%s&amp;quot; name toBuy instructions&lt;/pre&gt;

&lt;p&gt;本例不仅展示了如何将两个类型声明在&amp;#8220;一块&amp;#8221;，还显示了如何访问记录的字段值。可以看到&lt;strong&gt;访问记录的字段要比访问元组的值更为方便&lt;/strong&gt;。

  &lt;br /&gt;也可以对记录类型应用模式匹配：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type couple = { him : string; her : string }&lt;br /&gt;let couples =&lt;br /&gt;    [ { him = &amp;quot;Brad&amp;quot;; her = &amp;quot;Angelina&amp;quot; };&lt;br /&gt;      { him = &amp;quot;Becks&amp;quot;; her = &amp;quot;Posh&amp;quot; };&lt;br /&gt;      { him = &amp;quot;Chris&amp;quot;; her = &amp;quot;Gwyneth&amp;quot; } ]&lt;br /&gt;     &lt;br /&gt;let rec findDavid list =&lt;br /&gt;    match list with&lt;br /&gt;    | { him = x; her = &amp;quot;Posh&amp;quot; } :: tail -&amp;gt; x&lt;br /&gt;    | _ :: tail -&amp;gt; findDavid tail&lt;br /&gt;    | [] -&amp;gt; failwith &amp;quot;Couldn&amp;#39;t find David&amp;quot;&lt;br /&gt;   &lt;br /&gt;print_string(findDavid couples)&lt;/pre&gt;

&lt;p&gt;首先创建了couple类型的列表，findDavid函数将对该列表进行模式匹配，可以将字段与常量值比较，如her = &amp;#8220;Posh&amp;#8221;；将字段值赋给标识符，如him = x；还可以使用&amp;#8220;_&amp;#8221;忽略某个字段的值。最后上面例子的打印结果：Becks。
  &lt;br /&gt;&lt;strong&gt;字段值也可以是函数&lt;/strong&gt;，这种技术将在本系列文章的第三部分介绍。

  &lt;br /&gt;&lt;strong&gt;Union类型&lt;/strong&gt;，有时称为sum类型或discriminated union，可将一组具有不同含义或结构的数据组合在一起。可与C语言中的联合或C#中的枚举类比。先来看个例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type Volume =&lt;br /&gt;| Liter of float&lt;br /&gt;| UsPint of float&lt;br /&gt;| ImperialPint of float&lt;/pre&gt;

&lt;p&gt;Volume类型属于Union类型，包含3个&lt;strong&gt;数据构造器&lt;/strong&gt;（Data Constructor），每个构造器都包含单一的float值。声明其实例非常简单：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let vol1 = Liter 2.5&lt;br /&gt;let vol2 = UsPint 2.5&lt;br /&gt;let vol3 = ImperialPint 2.5&lt;/pre&gt;

&lt;p&gt;事实上，通过Reflector可以看到，Liter、UsPint和ImperialPint是Volume类型的派生类。在将Union类型解析为其基本类型时，我们需要模式匹配。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let convertVolumeToLiter x =&lt;br /&gt;    match x with&lt;br /&gt;    | Liter x -&amp;gt; x&lt;br /&gt;    | UsPint x -&amp;gt; x * 0.473&lt;br /&gt;    | ImperialPint x -&amp;gt; x * 0.568&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;记录类型和Union类型都可以被参数化&lt;/strong&gt;（Parameterized）。参数化的意思是在一个类型的定义中，它使用了一个或多个其它类型，这些类型不是在定义中确定的，而是在该代码的客户代码中确定。这与前面提及的&lt;strong&gt;可变类型&lt;/strong&gt;是类似的概念。&lt;/p&gt;

&lt;p&gt;对于类型参数化，F#中有两种语法予以支持。来看第一种：&lt;/p&gt;

&lt;pre&gt;OCaml-Style&lt;br /&gt;type &amp;#39;a BinaryTree =&lt;br /&gt;    | BinaryNode of &amp;#39;a BinaryTree * &amp;#39;a BinaryTree&lt;br /&gt;    | BinaryValue of &amp;#39;a&lt;br /&gt;   &lt;br /&gt;let tree1 =&lt;br /&gt;    BinaryNode(&lt;br /&gt;        BinaryNode(BinaryValue 1, BinaryValue 2),&lt;br /&gt;        BinaryNode(BinaryValue 3, BinaryValue 4))&lt;/pre&gt;

&lt;p&gt;在type关键字和类型名称BinaryTree之家添加了&amp;#8217;a，而&amp;#8217;a就是可变的类型，它的确切类型将在使用它的代码中确定，这是OCaml风格的语法。在标识符tree1中，定义BinaryValue时用的值是1，编译器将&amp;#8217;a解析为int类型。再看看第二种语法：&lt;/p&gt;

&lt;pre&gt;.NET-Style&lt;br /&gt;type Tree&amp;lt;&amp;#39;a&amp;gt; =&lt;br /&gt;    | Node of Tree&amp;lt;&amp;#39;a&amp;gt; list&lt;br /&gt;    | Value of &amp;#39;a&lt;br /&gt;   &lt;br /&gt;let tree2 =&lt;br /&gt;    Node( [Node([Value &amp;quot;One&amp;quot;; Value &amp;quot;Two&amp;quot;]);&lt;br /&gt;        Node([Value &amp;quot;Three&amp;quot;; Value &amp;quot;Four&amp;quot;])])&lt;/pre&gt;

&lt;p&gt;这种语法更接近于C#中的泛型定义，是.NET风格的语法。在tree2中，&amp;#8217;a被解析为string类型。不管哪种语法，都是单引号后跟着字母，我们一般只使用单个字母。
  &lt;br /&gt;创建和使用参数化类型的实例跟非参数化类型的过程是一样的，因为编译器会自动推导参数化的类型。

  &lt;br /&gt;在本节中，我们逐一讨论了元组、记录和Union类型。通过Reflector可以看到，元组值是Tuple类型的实例，而Tuple实现了Microsoft.FSharp.Core.IStructuralHash和System.IComparable接口；记录和Union则直接实现了这两个接口。要了解IStructualHash接口的更多内容，请参考&lt;a href="http://blogs.msdn.com/jomo_fisher/archive/2007/09/17/adventures-in-f-discriminated-unions.aspx"&gt;Jome Fisher的文章&lt;/a&gt;。

  &lt;br /&gt;到这里，我们讨论完了如何定义类型、创建和使用它们的实例，却未提及对它们的修改。那是因为我们没法修改这些类型的值，这是函数式编程的特性之一。但F#提供了多种编程范式，对某些类型来说，它们是可修改的，这将在下一部分（命令式编程）进行介绍。

  &lt;br /&gt;&lt;strong&gt;异常处理（Exception Handling） &lt;/strong&gt;

  &lt;br /&gt;&lt;strong&gt;在F#中，异常的定义类似于Union类型的定义，而异常处理的语法则类似于模式匹配&lt;/strong&gt;。使用exception关键字来定义异常，可选地，如果异常包含了数据我们应当声明数据的类型，注意是可以包含多种类型数据的：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;exception SimpleException&lt;br /&gt;exception WrongSecond of int&lt;br /&gt;// Hour, MInute, Second&lt;br /&gt;exception WrongTime of int * int * int&lt;/pre&gt;

&lt;p&gt;要抛出一个异常，可使用raise关键字。F#还提供了另一种方法，如果仅仅想抛出一个包含文本信息的异常，可以使用failwith函数，该函数抛出一个FailureException类型的异常。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let testTime() =&lt;br /&gt;    try&lt;br /&gt;        let now = System.DateTime.Now in&lt;br /&gt;        if now.Second &amp;lt; 10 then&lt;br /&gt;            raise SimpleException&lt;br /&gt;        elif now.Second &amp;lt; 30 then&lt;br /&gt;            raise (WrongSecond now.Second)&lt;br /&gt;        elif now.Second &amp;lt; 50 then&lt;br /&gt;            raise (WrongTime (now.Hour, now.Minute, now.Second))&lt;br /&gt;        else&lt;br /&gt;            failwith &amp;quot;Invalid Second&amp;quot;&lt;br /&gt;    with&lt;br /&gt;        | SimpleException -&amp;gt;&lt;br /&gt;            printf &amp;quot;Simple exception&amp;quot;&lt;br /&gt;        | WrongSecond s -&amp;gt;&lt;br /&gt;            printf &amp;quot;Wrong second: %i&amp;quot; s&lt;br /&gt;        | WrongTime(h, m, s) -&amp;gt;&lt;br /&gt;            printf &amp;quot;Wrong time: %i:%i:%i&amp;quot; h m s&lt;br /&gt;        | Failure str -&amp;gt;&lt;br /&gt;            printf &amp;quot;Error msg: %s&amp;quot; str&lt;br /&gt;           &lt;br /&gt;testTime()&lt;/pre&gt;

&lt;p&gt;这个例子展示了如何抛出和捕获各种异常，如果你熟悉C#中的异常处理，对此应该不会感到陌生。&lt;/p&gt;

&lt;p&gt;与C#类似，F#也支持finally关键字，它当然要与try关键字一起使用。不管是否有异常抛出，finally块中的代码都会执行，在下面的例子中使用finally块来保证文件得以正确地关闭和释放：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let writeToFile() =&lt;br /&gt;    let file = System.IO.File.CreateText(&amp;quot;test.txt&amp;quot;) in&lt;br /&gt;    try&lt;br /&gt;        file.WriteLine(&amp;quot;Hello F# Fans&amp;quot;)&lt;br /&gt;    finally&lt;br /&gt;        file.Dispose()&lt;br /&gt;       &lt;br /&gt;writeToFile()&lt;/pre&gt;

&lt;p&gt;需要注意的是，由于CLR架构的原因，&lt;strong&gt;抛出异常的代价是很昂贵的，因此要谨慎使用&lt;/strong&gt;。

  &lt;br /&gt;&lt;strong&gt;延迟求值（或惰性求值，Lazy Evaluation） &lt;/strong&gt;

  &lt;br /&gt;第一次接触Lazy的东西是iBATIS中的LazyLoad，也就是延迟加载，它并不是在开始时加载所有数据，而是在必要时才进行读取。延迟求值与此类似，除了性能的提升外，还可用于创建无限的数据结构。

  &lt;br /&gt;延迟求值与函数式编程语言关系密切，其原理是如果一种语言没有副作用，编译器或运行时可随意选择表达式的求值顺序。F#允许函数具有副作用，因此编译器或运行时不能够按随意地顺序对函数求值，可以说&lt;strong&gt;F#具有严格的求值顺序或 F#是一种严格的语言&lt;/strong&gt;。

  &lt;br /&gt;如果要利用延迟求值的特性，必须要显式地声明哪些表达式的求值需要延迟，这个要使用lazy关键字。如果需要对该表达式求值，则要调用Lazy模块的force函数。&lt;strong&gt;在调用force函数的时候，它会计算表达式的值，而所求得的值会被缓存起来，再次对表达式应用force函数时，所得的值其实是缓存中的值&lt;/strong&gt;。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let sixtyWithSideEffect = lazy(printfn &amp;quot;Hello, sixty!&amp;quot;; 30 + 30)&lt;br /&gt;&lt;br /&gt;print_endline &amp;quot;Force value the first time:&amp;quot;&lt;br /&gt;let actualValue1 = Lazy.force sixtyWithSideEffect&lt;br /&gt;&lt;br /&gt;print_endline &amp;quot;Force value the second time:&amp;quot;&lt;br /&gt;let actualValue2 = Lazy.force sixtyWithSideEffect&lt;/pre&gt;

&lt;p&gt;打印结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;Force value the first time:&lt;br /&gt;Hello, sixty!&lt;br /&gt;Force value the second time:&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;
    &lt;br /&gt;小节&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;本文继续讨论F#函数式编程范式的核心内容，主要是模式匹配、自定义类型、异常处理和延迟求值等内容，至此，F#的函数式编程的相关内容就介绍完了。模式匹配可以很大程度上简化我们的程序；自定义类型则可以帮助我们更好地组织程序；延迟求值不仅能够提升性能，还可用于创建无限的数据结构，比如自然数序列。另外，在开发F#程序时，建议常用Reflector来看看编译后代码的样子，来了解它优雅的函数式编程背后到底是什么。在下一站，我们将看看命令式编程的风景。&lt;/p&gt;

&lt;p&gt;参考：
  &lt;br /&gt;《Foundations of F#》 by Robert Pickering

  &lt;br /&gt;《Expert F#》 by Don Syme , Adam Granicz , Antonio Cisternino

  &lt;br /&gt;《&lt;a href="http://research.microsoft.com/fsharp/manual/spec2.aspx"&gt;F# Specs&lt;/a&gt;》&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;我们了解了如何使用F#进行纯粹的函数式编程。但是在一些情况下，比如I/O，几乎不能避免改变状态，也就是说会带来side effect。F#并不强求你以无状态的方式编写程序，它提供了可修改（mutable）的标识符来解决这类问题，同时它还提供了其它的程序结构以支持命令式编程。现在就来对这些特性探个究竟。
  &lt;br /&gt;首先是unit类型，这种类型表示&amp;#8220;没有值&amp;#8221;。然后是F#如何处理可修改的值。最后来看看如何在F#中使用.NET类库，包括如何调用静态方法、创建对象并使用其成员、使用类的索引器和事件以及F#中的|&amp;gt;操作符。

  &lt;br /&gt;&lt;strong&gt;unit类型&lt;/strong&gt;

  &lt;br /&gt;没有参数和返回值的函数的类型为unit，它类似于C#中的void，或者说CLR中的&lt;strong&gt;System.Void&lt;/strong&gt;。对于使用函数式编程语言的开发人员来说，不接受参数、无返回值的函数没多大意义。而在命令式编程中，由于side effect的存在，这样的函数仍有意义。unit类型表示为一对括号&amp;#8220;()&amp;#8221;。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let main() =&lt;br /&gt;    ()&lt;/pre&gt;

&lt;p&gt;在这个例子中，main函数的类型为unit -&amp;gt; unit，也就是说它既不接受参数，也无返回值。第一对括号使得main成为一个函数而不是一个简单的值。第二对括号告诉编译器，main函数什么值也不返回。
  &lt;br /&gt;&lt;strong&gt;注意&lt;/strong&gt;：仅仅将函数命名为main不表示它就是程序的入口，它不会自动执行（像C#的Main方法那样），要执行它，需要在源文件的结尾处调用：main()，在后面的文章中将介绍如何指定F#程序的入口。

  &lt;br /&gt;再来看看如何调用unit类型的函数，有两种方式：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let () = main()&lt;br /&gt;// -- or -- &lt;br /&gt;main()&lt;/pre&gt;

&lt;p&gt;我们还可以在函数内部连续多次调用unit类型的函数&amp;#8212;&amp;#8212;只要保证它们的缩进是一样的即可：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let poem() =&lt;br /&gt;    print_endline &amp;quot;I sent thee late a rosy wreath&amp;quot;&lt;br /&gt;    print_endline &amp;quot;Not so much honouring thee&amp;quot;&lt;br /&gt;    print_endline &amp;quot;As giving it a hope that there&amp;quot;&lt;br /&gt;    print_endline &amp;quot;It could not withered be&amp;quot;&lt;br /&gt;&lt;br /&gt;poem()&lt;/pre&gt;

&lt;p&gt;这是《Song to Celia》中的四句诗词，print_endline函数的类型为string -&amp;gt; unit，我们知道函数的返回值为其函数体内最后一步运算的值，所以poem的类型为unit -&amp;gt; unit。
  &lt;br /&gt;并不是说只有unit类型的函数可以这么用，但是调用非unit类型的函数时编译器会报告一个警告，因为它可能会有副作用（side effect），比如：warning FS0020: This expression should have type &amp;#39;unit&amp;#39;, but has type &amp;#39;string&amp;#39;，我们看到警告总会感觉不舒服。F#提供了一些机制可将这些警告消除，即将函数转换为unit类型的函数。事实上，这种需求在使用F#库时不多，在使用由其它语言编写的.NET类库时会更多些。看下面的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;let getString() = &amp;quot;foo bar&amp;quot;&lt;br /&gt;&lt;br /&gt;let _ = getString()&lt;br /&gt;// -- or --&lt;br /&gt;ignore(getString())&lt;br /&gt;// -- or --&lt;br /&gt;getString() |&amp;gt; ignore&lt;/pre&gt;

&lt;p&gt;首先是函数getString的定义，下面的三行则是将其转换为unit类型函数的三种方式。第一种是使用下划线&amp;#8220;_&amp;#8221;，它在前面已经出现过几次，它一般表示我们对某些值不感兴趣；既然不感兴趣，那就可以忽略（ignore）了，这就是第二种方式：ignore函数；第三种方式使用了&amp;#8220;|&amp;gt;&amp;#8221;操作符，它本质上同第二种一样。&amp;#8220;|&amp;gt;&amp;#8221;操作符会在稍后介绍。
  &lt;br /&gt;&lt;strong&gt;mutable关键字 &lt;/strong&gt;

  &lt;br /&gt;在探险之旅（二）中我们知道可以使用let关键字将值绑定至标识符，在某些情况下，我们还可以&lt;strong&gt;重定义（redefine）&lt;/strong&gt;标识符或者&lt;strong&gt;绑定（rebind）&lt;/strong&gt;新的值，但是不能直接修改它的值。显然，对于我们这些用惯了命令式编程语言的人来说，这实在有些不爽，因为&lt;strong&gt;这些语言以修改变量的值作为最基本的运算方式&lt;/strong&gt;。既然F#也支持命令式编程范式，它当然也能让你修改标识符的值。这就是mutable关键字和&amp;#8220;&amp;lt;-&amp;#8221;操作符，&amp;#8220;&amp;lt;-&amp;#8221;的类型为unit（操作符也是函数），下面的例子对此作了演示：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let mutable phrase = &amp;quot;Good good study, &amp;quot;&lt;br /&gt;print_endline phrase&lt;br /&gt;phrase &amp;lt;- &amp;quot;day day up.&amp;quot;&lt;br /&gt;print_endline phrase&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;Good good study,&lt;br /&gt;day day up.&lt;/pre&gt;

&lt;p&gt;这看起来像是重定义标识符，其实不然。修改标识符时，只能修改它的值而不能修改类型；重定义时可同时改变类型和值（这本质上是定义了一个新的标识符）。事实上，如果你尝试修改标识符的类型，编译器会给你一个错误。另外，它们还有一个重要的差别，即它们的可见性（或者说修改行为的作用域）。在重定义标识符的时候，修改仅仅在新标识符的作用域内有效，一旦出了这个作用域，它就会回复到旧有的值；对于可修改的标识符来说，任何修改都是永久性，与作用域无关。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let redefineX() =&lt;br /&gt;    let x = &amp;quot;One&amp;quot;&lt;br /&gt;    printfn &amp;quot;Redefining: \r\nx = %s&amp;quot; x&lt;br /&gt;    if true then&lt;br /&gt;        let x = &amp;quot;Two&amp;quot;&lt;br /&gt;        printfn &amp;quot;x = %s&amp;quot; x&lt;br /&gt;    else ()&lt;br /&gt;    printfn &amp;quot;x = %s&amp;quot; x&lt;br /&gt;    &lt;br /&gt;let mutableX() =&lt;br /&gt;    let mutable x = &amp;quot;One&amp;quot;&lt;br /&gt;    printfn &amp;quot;Mutating: \r\nx = %s&amp;quot; x&lt;br /&gt;    if true then&lt;br /&gt;        x &amp;lt;- &amp;quot;Two&amp;quot;&lt;br /&gt;        printfn &amp;quot;x = %s&amp;quot; x&lt;br /&gt;    else ()&lt;br /&gt;    printfn &amp;quot;x = %s&amp;quot; x&lt;br /&gt;    &lt;br /&gt;redefineX()&lt;br /&gt;mutableX()&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;Redefining:&lt;br /&gt;X = One&lt;br /&gt;X = Two&lt;br /&gt;X = One&lt;br /&gt;Mutating:&lt;br /&gt;X = One&lt;br /&gt;X = Two&lt;br /&gt;X = Two&lt;/pre&gt;

&lt;p&gt;可修改的标识符也有其局限性，在子函数内不能修改它的值。而这也是ref类型的来由，稍后你会看到。
  &lt;br /&gt;&lt;strong&gt;定义可修改的记录（Record）类型 &lt;/strong&gt;

  &lt;br /&gt;默认情况下，记录类型是不可变的。不过F#提供了一种特殊的语法，使得我们可以修改记录类型的字段值，即在字段前使用&lt;strong&gt;mutable关键字&lt;/strong&gt;。需要注意的是，&lt;strong&gt;这种操作改变的是记录字段的内容而不是记录本身&lt;/strong&gt;。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type Couple = &lt;br /&gt;    {her : string; mutable him : string}&lt;br /&gt;let couple = {her = &amp;quot;Elizabeth Taylor&amp;quot;; him = &amp;quot;Nicky Hilton&amp;quot;}&lt;br /&gt;&lt;br /&gt;let print o = printf &amp;quot;%A \r\n&amp;quot; o&lt;br /&gt;&lt;br /&gt;let changeCouple() =&lt;br /&gt;    print couple;&lt;br /&gt;    couple.him &amp;lt;- &amp;quot;Michael Wilding&amp;quot;;&lt;br /&gt;    print couple;&lt;br /&gt;    couple.him &amp;lt;- &amp;quot;Michael Todd&amp;quot;;&lt;br /&gt;    print couple;&lt;br /&gt;    &lt;br /&gt;changeCouple()&lt;/pre&gt;

&lt;p&gt;通过Couple类型的定义可知，him字段是可修改的，就像changeCouple中的代码，但如果尝试修改her的值就会遭遇编译错误。
  &lt;br /&gt;&lt;strong&gt;ref类型&lt;/strong&gt;

  &lt;br /&gt;&lt;strong&gt;ref类型是一种状态进行修改的简单方式&lt;/strong&gt;。ref类型其实是&lt;strong&gt;包含一个可修改字段的record类型&lt;/strong&gt;，它定义在F#库中，伴随它的还有两个操作符，它们使得操作ref类型更为方便：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let ref x = { contents = x }&lt;br /&gt;let (:=) x y = x.contents &amp;lt;- y&lt;br /&gt;let (!) x = x.contents&lt;/pre&gt;

&lt;p&gt;ref&amp;#8220;函数&amp;#8221;将输入的值&amp;#8220;装入&amp;#8221;一个记录类型，同时用&amp;#8220;:=&amp;#8221;操作符来进行赋值，&amp;#8220;!&amp;#8221;来取值。进一步分析，ref&amp;#8220;函数&amp;#8221;的类型为a&amp;#8217; -&amp;gt; Ref&amp;lt;a&amp;#8217;&amp;gt;，可以了解到&amp;#8220;装入&amp;#8221;的记录类型为Ref&amp;lt;a&amp;#8217;&amp;gt;，由此可知使用了&lt;strong&gt;类型参数化（type parameterization）&lt;/strong&gt;，这个概念前面部分已经介绍过了。这意味着ref可以接受任意类型的值，但是一经赋值，其类型也就固定了。Ref&amp;lt;a&amp;#8217;&amp;gt;类型暴露了Value属性，我们也可以通过它来获取或设置ref类型的值。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let phrase = ref &amp;quot;Inconsistency&amp;quot;&lt;/pre&gt;

&lt;p&gt;考虑一个简单的问题，求一个整型数组所有元素的和。先看C#怎么做：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;static int TotalArray(int[] array)&lt;br /&gt;{&lt;br /&gt;    int total = 0;&lt;br /&gt;    foreach (int element in array)&lt;br /&gt;    {&lt;br /&gt;        total += element;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return total;&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;再看看F#的版本：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let totalArray (intArray : int array) =&lt;br /&gt;    let x = ref 0&lt;br /&gt;    for n in intArray do&lt;br /&gt;        x := !x + n&lt;br /&gt;    !x&lt;/pre&gt;

&lt;p&gt;可以看到F#的命令式编程范式下与C#何其相似！
  &lt;br /&gt;&lt;strong&gt;数组（Array） &lt;/strong&gt;

  &lt;br /&gt;数组算得上是我们最熟悉的数据结构了。&lt;strong&gt;F#中的数组基于BCL中的System.Array类型，是一种可修改的集合类型&lt;/strong&gt;。数组与列表相对，数组中的值是可修改的，而列表中的值则不能；列表的容量（长度）可以动态增大，数组则不能。一维数组又时被称为向量（Vector），多维数组有时被称为矩阵（Matrix）。定义数组时，将各项置于&amp;#8220;[|&amp;#8221;和&amp;#8220;|]&amp;#8221;中，各项间用&amp;#8220;;&amp;#8221;隔开。

  &lt;br /&gt;下面的例子演示了如何对数组进行读取和写入操作。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;// 定义&lt;br /&gt;let rhymeArray = [| &amp;quot;Hello&amp;quot;; &amp;quot;F#&amp;quot; |]&lt;br /&gt;   &lt;br /&gt;// 读取  &lt;br /&gt;let firstPiggy = rhymeArray.[0]&lt;br /&gt;let secondPiggy = rhymeArray.[1]&lt;br /&gt;&lt;br /&gt;// 写入&lt;br /&gt;rhymeArray.[0] &amp;lt;- &amp;quot;Byebye&amp;quot;&lt;br /&gt;rhymeArray.[1] &amp;lt;- &amp;quot;my friend&amp;quot;&lt;br /&gt;&lt;br /&gt;// 输出&lt;br /&gt;print_endline firstPiggy&lt;br /&gt;print_endline secondPiggy&lt;br /&gt;print_any rhymeArray&lt;/pre&gt;

&lt;p&gt;数组跟列表一样，也采用了类型参数化，数组的类型为其元素的类型，因此rhymeArray的类型为string array，也可写作string[]。
  &lt;br /&gt;F#中的多维数组可分为两类：&lt;strong&gt;交错数组（jagged array&lt;/strong&gt;）和&lt;strong&gt;规则数组&lt;/strong&gt;。交错数组，表示数组的数组，就是说最外部数组的元素也是数组（称为内部数组），内部数组的长度不必相同。而规则数组，事实上整个数组作为一个对象，其内部数组的长度是相同的。

  &lt;br /&gt;先来看看交错数组的用法：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let jaggedArray = [| [| &amp;quot;one&amp;quot; |]; [| &amp;quot;two&amp;quot;; &amp;quot;three&amp;quot; |] |]&lt;br /&gt;let singleDimension = jaggedArray.[0]&lt;br /&gt;let itemOne = singleDimension.[0]&lt;br /&gt;let itemTwo = jaggedArray.[1].[0]&lt;br /&gt;&lt;br /&gt;printfn &amp;quot;%s %s&amp;quot; itemOne itemTwo // one two&lt;/pre&gt;

&lt;p&gt;jaggedArray的类型为string array array，这也是为什么说它是数组的数组，操作规则数组的语法有所不同：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let square = Array2.create 2 2 0&lt;br /&gt;square.[0,0] &amp;lt;- 1&lt;br /&gt;square.[0,1] &amp;lt;- 2&lt;br /&gt;square.[1,0] &amp;lt;- 3&lt;br /&gt;square.[1,1] &amp;lt;- 4&lt;br /&gt;printf &amp;quot;%A \r\n&amp;quot; square // [| [|1; 2|]; [|3; 4|] |]&lt;/pre&gt;

&lt;p&gt;square的类型为int[,]。
  &lt;br /&gt;&lt;strong&gt;注意&lt;/strong&gt;：要编写.NET 1.1 和.NET 2.0兼容的代码，需要使用Microsoft.FSharp.Compatibility命名空间的CompatArray和CompatMatrix类。

  &lt;br /&gt;&lt;strong&gt;数组推导（Array Comprehension） &lt;/strong&gt;

  &lt;br /&gt;前面介绍过了关于列表和序列的推导语法。我们也可以使用类似的语法进行数组推导。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let chars = [|&amp;#39;1&amp;#39; .. &amp;#39;9&amp;#39;|]&lt;br /&gt;&lt;br /&gt;let squares =&lt;br /&gt;    [| for x in 1 .. 9&lt;br /&gt;        -&amp;gt; x, x * x |]&lt;br /&gt;printfn &amp;quot;%A&amp;quot; chars&lt;br /&gt;printfn &amp;quot;%A&amp;quot; squares&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：本文中的代码均在F# 1.9.4.17版本下编写，在F# CTP 1.9.6.0版本下可能不能通过编译。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;控制流程（Control Flow） &lt;/strong&gt;

  &lt;br /&gt;我们初步了解了F#在函数式编程范式下的控制流程，即if, elif, then, else等组成的结构。在命令式编程范式下，F#提供了更多的控制流程支持，包括if，while和for。

  &lt;br /&gt;在命令式编程范式下的if结构与函数式编程下对应结构的主要差别在于，对于if分支，调用的函数为unit类型（即无返回值），而且并不要求必须使用else分支：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;if System.DateTime.Now.DayOfWeek = System.DayOfWeek.Thursday then&lt;br /&gt;    print_endline &amp;quot;Thursday play list: lazy afternoon&amp;quot;&lt;/pre&gt;

&lt;p&gt;这里print_endline函数的类型为string -&amp;gt; int。尽管else分支不是必须的，但如果需要，你也可以加上，不过else分支也必须为unit类型。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;if System.DateTime.Now.DayOfWeek = System.DayOfWeek.Thursday then&lt;br /&gt;    print_endline &amp;quot;Thursday play list: lazy afternoon&amp;quot;&lt;br /&gt; else&lt;br /&gt;    print_endline &amp;quot;Alt play list: pop music&amp;quot;&lt;/pre&gt;

&lt;p&gt;至此，不管if结构的分支是否返回值，我们都有办法表示，这样就跟C#的if结构一致了。
  &lt;br /&gt;在C#中，如果一个分支的语句多于一条，需要使用花括号，而在F#中，分支所包含的语句要通过缩进来表示。

  &lt;br /&gt;for循环是命令式编程中一种常见的结构。如果你有过C#或VB.NET的经验，那么很容易理解：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let sentence = [| &amp;quot;To &amp;quot;; &amp;quot;live &amp;quot;; &amp;quot;is &amp;quot;; &amp;quot;to &amp;quot;; &amp;quot;function.&amp;quot; |]&lt;br /&gt;&lt;br /&gt;for index = 0 to Array.length sentence - 1 do&lt;br /&gt;    System.Console.Write sentence.[index]&lt;/pre&gt;

&lt;p&gt;在C#中，for循环是否执行需要看中间的bool表达式的结果，而这里则是看局部值index是否在指定的范围内，而且初始值要小于终止值。F#还提供了另一种for循环结构：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let whitePollution = [| &amp;quot;This term refers to &amp;quot;; &amp;quot;pollution caused by &amp;quot;; &lt;br /&gt;    &amp;quot;litter of used plastic bags, &amp;quot;; &amp;quot;polystyrene cups, &amp;quot;;&lt;br /&gt;    &amp;quot;food containers and paper.&amp;quot; |]&lt;br /&gt;    &lt;br /&gt;for index = Array.length whitePollution - 1 downto 0 do&lt;br /&gt;    System.Console.Write whitePollution.[index]&lt;/pre&gt;

&lt;p&gt;此时index的值将以递减顺序变化。
  &lt;br /&gt;while循环也较为简单，与C#很相似，直接看个例子吧：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;// 压洲&lt;br /&gt;let pressureContinent = ref [ &amp;quot;This phrase&amp;#39;s pronunciation is &amp;quot;;&lt;br /&gt;    &amp;quot;similar to \&amp;quot;Asia\&amp;quot; in Chinese, &amp;quot;; &amp;quot;but it means &amp;quot;;&lt;br /&gt;    &amp;quot;a continent of pressure.&amp;quot; ]&lt;br /&gt;    &lt;br /&gt;while (List.nonempty !pressureContinent) do&lt;br /&gt;    System.Console.Write(List.hd !pressureContinent);&lt;br /&gt;    pressureContinent := List.tl !pressureContinent&lt;br /&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;循环推导（Loops over Comprehensions） &lt;/strong&gt;

  &lt;br /&gt;可以使用for循环来枚举一个集合，这种方式与C#中的foreach结构类似。下面的例子对一个字符串数组进行枚举。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let words = [| &amp;quot;Red&amp;quot;; &amp;quot;Lorry&amp;quot;; &amp;quot;Yellow&amp;quot;; &amp;quot;Lorry&amp;quot; |]&lt;br /&gt;&lt;br /&gt;for word in words do&lt;br /&gt;    print_endline word&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;调用.NET类库中的静态方法和属性 &lt;/strong&gt;

  &lt;br /&gt;F#中的命令式编程有一个极为有用的特性，它能够调用由任意.NET语言编写的类库，这包括BCL本身。不过在调用由F#编写的类库和由其它语言编写的类库时有所不同，因为F#类库拥有额外的元数据，比如一个方法是否接受一个元组或者其参数是否可被柯里化，这些元数据专用于F#。Microsoft.FSharp.Reflection API的产生很大程度上是由于这些元数据，这些API用于在F#和.NET的元数据间进行交互。

  &lt;br /&gt;调用类的静态或实例方法和属性的基本语法是相同的，而在调用由非F#类库中的方法时必须使用括号（在F#中通常可用空格）。非F#类库中的方法不能被柯里化，方法本身也不是值，因此不能作为参数传递。遵循了这些规则，调用非F#类库的方法就变得直白、简单了。先来看看如何使用静态属性和方法：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;open System.IO&lt;br /&gt;&lt;br /&gt;if File.Exists(&amp;quot;test.txt&amp;quot;) then&lt;br /&gt;    print_endline &amp;quot;test.txt is present&amp;quot;&lt;br /&gt;else&lt;br /&gt;    print_endline &amp;quot;test.txt does not exist&amp;quot;&lt;/pre&gt;

&lt;p&gt;Exists方法是File类的静态方法，这里的用法跟C#或VB.NET中很像。但这里的代码风格不太像函数式编程的风格，我们可以&lt;strong&gt;将.NET类库的方法做个简单的包装&lt;/strong&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let exists filePath = File.Exists(filePath)&lt;br /&gt;let files = [&amp;quot;test1.txt&amp;quot;; &amp;quot;test2.txt&amp;quot;; &amp;quot;test3.txt&amp;quot;]&lt;br /&gt;&lt;br /&gt;let results = List.map exists files&lt;br /&gt;print_any results&lt;/pre&gt;

&lt;p&gt;上面的代码功能是对列表中的文件逐一进行检测，看它是否存在。exists函数对Exist方法做了包装，这样就可以以函数式编程的风格调用它了。
  &lt;br /&gt;如果调用的.NET方法有很多参数，可能会忘掉某个参数的用途，在VS中可以查看参数信息（快捷键Ctrl+K, P）。而在F#中我们还可以使用&lt;strong&gt;具名参数（named argumengs）&lt;/strong&gt;：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;open System.IO&lt;br /&gt;&lt;br /&gt;let file = File.Open(path = &amp;quot;test.txt&amp;quot;,&lt;br /&gt;                    mode = FileMode.Append,&lt;br /&gt;                    access = FileAccess.Write,&lt;br /&gt;                    share = FileShare.None)&lt;br /&gt;                    &lt;br /&gt;print_any file.Length&lt;br /&gt;file.Close()&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;使用.NET类库中的对象和实例成员 &lt;/strong&gt;

  &lt;br /&gt;除了类的静态成员，我们也可以创建类的实例并使用它的成员（字段、属性、事件、方法）：&lt;/p&gt;

&lt;pre&gt;#light&lt;br /&gt;open System.IO&lt;br /&gt;&lt;br /&gt;let file = new FileInfo(&amp;quot;notExisting.txt&amp;quot;)&lt;br /&gt;if not file.Exists then&lt;br /&gt;    using(file.CreateText()) (fun stream -&amp;gt;&lt;br /&gt;        stream.WriteLine(&amp;quot;hello, f#&amp;quot;))&lt;br /&gt;    file.Attributes &amp;lt;- FileAttributes.ReadOnly&lt;br /&gt;    &lt;br /&gt;print_endline file.FullName&lt;/pre&gt;

&lt;p&gt;这段代码引用命名空间，创建FileInfo类的实例，检查文件是否存在，（如果不存在的话）创建文件，写入文本，设置属性值，熟悉C#或VB.NET的你是否感觉很眼熟？这里创建的实例很像记录类型，它引用的对象本身（file）是不能修改的，但它包含的内容则是可以修改的（Attributes属性）。设置属性值时要用&amp;#8220;&amp;lt;-&amp;#8221;操作符。using其实是一个操作符，用于清理资源（对比下C#中的using语句）。
  &lt;br /&gt;再考虑一下上面的例子，中间的两步是创建实例，设置属性，这是我们经常做的事情：&lt;/p&gt;

&lt;pre&gt;C# Code&lt;br /&gt;Person person = new Person(1);&lt;br /&gt;person.Name = &amp;quot;Steve&amp;quot;;&lt;br /&gt;person.BirthOn = DateTime.Now;&lt;/pre&gt;

&lt;p&gt;F#中还可以把上述过程简化：&lt;/p&gt;

&lt;pre&gt;F# Code&lt;br /&gt;open System.IO&lt;br /&gt;let fileName = &amp;quot;test.txt&amp;quot;&lt;br /&gt;let file =&lt;br /&gt;    if File.Exists(fileName) then&lt;br /&gt;        Some(new FileInfo(fileName, Attributes = FileAttributes.ReadOnly))&lt;br /&gt;    else&lt;br /&gt;        None&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;使用.NET类库中的索引器（Indexer） &lt;/strong&gt;

  &lt;br /&gt;索引器是.NET中的一个重要的概念，它使得一个集合类看起来像是一个数组。它本质上是名为Item的特殊属性。基于上述两点，F#提供了两种方式来访问索引器。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;open System.Collections.Generic&lt;br /&gt;&lt;br /&gt;let stringList =&lt;br /&gt;    let temp = new ResizeArray&amp;lt;string&amp;gt;() in&lt;br /&gt;    temp.AddRange([|&amp;quot;one&amp;quot;; &amp;quot;two&amp;quot;; &amp;quot;three&amp;quot;|]);&lt;br /&gt;    temp&lt;br /&gt;    &lt;br /&gt;let itemOne = stringList.Item(0)&lt;br /&gt;let itemTwo = stringList.[1]&lt;br /&gt;&lt;br /&gt;printfn &amp;quot;%s %s&amp;quot; itemOne itemTwo&lt;/pre&gt;

&lt;p&gt;第一种以属性的方式访问，第二种以数组的方式访问。
  &lt;br /&gt;注意：&lt;strong&gt;上面例子中的代码很简单，却展示了F#中的一种常用模式&lt;/strong&gt;。在创建标识符stringList时，首先将其实例化，然后调用它的实例成员（AddRange）设置状态，最后返回。

  &lt;br /&gt;&lt;strong&gt;使用.NET类库中的事件（Event） &lt;/strong&gt;

  &lt;br /&gt;对于Windows Forms和Web Forms的开发人员，恐怕没有不知道事件的含义吧？我们可以将函数附加到事件上，比如Button的Click事件，这些附加的函数有时称为事件处理器（Event Handler）。

  &lt;br /&gt;向事件添加一个处理器函数也很简单。每个事件都暴露了Add方法，由于事件在非F#类库中定义，因此Add方法需要带有括号。在F#中，&lt;strong&gt;通常可使用匿名函数作为处理器函数&lt;/strong&gt;。

  &lt;br /&gt;下面的例子使用了Timer类及其Elapsed事件：&lt;/p&gt;

&lt;pre&gt;F# Code-Timer的Elapsed事件&lt;br /&gt;#light&lt;br /&gt;open System.Timers&lt;br /&gt;module WF = System.Windows.Forms&lt;br /&gt;&lt;br /&gt;let timer =&lt;br /&gt;    let temp = new Timer()&lt;br /&gt;    temp.Interval &amp;lt;- 1000.0&lt;br /&gt;    temp.Enabled &amp;lt;- true&lt;br /&gt;    let messageNo = ref 0&lt;br /&gt;    temp.Elapsed.Add(fun _ -&amp;gt;&lt;br /&gt;        let messages = [&amp;quot;bet&amp;quot;; &amp;quot;this&amp;quot;; &amp;quot;gets&amp;quot;;&lt;br /&gt;        &amp;quot;really&amp;quot;; &amp;quot;annoying&amp;quot;; &amp;quot;very&amp;quot;; &amp;quot;quickly&amp;quot;;]&lt;br /&gt;        WF.MessageBox.Show(List.nth messages !messageNo) |&amp;gt; ignore&lt;br /&gt;        messageNo := (!messageNo + 1) % (List.length messages))&lt;br /&gt;    temp&lt;br /&gt;    &lt;br /&gt;print_endline &amp;quot;Whack the return to finish!&amp;quot;&lt;br /&gt;read_line() |&amp;gt; ignore&lt;br /&gt;timer.Enabled &amp;lt;- false&lt;/pre&gt;

&lt;p&gt;能附加事件处理器，当然也能移除事件处理器，这需要使用RemoveHandler方法。RemoveHandler方法接受一个委托值，这个委托值封装了.NET中的方法，使得它可在方法间像值一样传递，不过在用&lt;strong&gt;RemoveHandler前要用AddHandler添加事件处理器，而不是Add方法&lt;/strong&gt;。

  &lt;br /&gt;&lt;strong&gt;对.NET类型应用模式匹配 &lt;/strong&gt;

  &lt;br /&gt;模式匹配使得我们可以针对不同的值进行不同的运算。此外，F#还允许对.NET类型进行匹配，这要用到:?操作符。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;let simpleList = [box 1; box 2.0; box &amp;quot;three&amp;quot;]&lt;br /&gt;    &lt;br /&gt;let recognizeType (item : obj) =&lt;br /&gt;    match item with&lt;br /&gt;    | :? System.Int32 -&amp;gt; print_endline &amp;quot;An integer&amp;quot;&lt;br /&gt;    | :? System.Double -&amp;gt; print_endline &amp;quot;A double&amp;quot;&lt;br /&gt;    | :? System.String -&amp;gt; print_endline &amp;quot;A string&amp;quot;&lt;br /&gt;    | _ -&amp;gt; print_endline &amp;quot;Unkown type&amp;quot;&lt;/pre&gt;

&lt;p&gt;我们不可能罗列所有的.NET类型，最后一行的作用在于匹配所有的其它类型。很自然的，在对类型进行匹配时，我们不仅想知道类型，还想了解当前的值，可以这么做：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;let simpleList = [box 1; box 2.0; box &amp;quot;three&amp;quot;]&lt;br /&gt;&lt;br /&gt;let recognizeType (item : obj) =&lt;br /&gt;    match item with&lt;br /&gt;    | :? System.Int32 as x -&amp;gt; printfn &amp;quot;An integer: %i&amp;quot; x&lt;br /&gt;    | :? System.Double as x -&amp;gt; printfn &amp;quot;A double: %f&amp;quot; x&lt;br /&gt;    | :? System.String as x -&amp;gt; printfn &amp;quot;A string: %s&amp;quot; x&lt;br /&gt;    | x -&amp;gt; printfn &amp;quot;An object: %A&amp;quot; x&lt;/pre&gt;

&lt;p&gt;在&lt;a href="http://www.cnblogs.com/anderslly/archive/2008/09/06/fs-adventure-fp-part-three.html"&gt;前面的文章&lt;/a&gt;中我们了解了异常处理的基本用法，这里的技术也可用在异常处理中，因为我们往往会根据类型捕获异常。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let now = System.DateTime.Now&lt;br /&gt;System.Console.WriteLine(now)&lt;br /&gt;&lt;br /&gt;try&lt;br /&gt;    if now.Second % 3 = 0 then&lt;br /&gt;        raise (new System.Exception())&lt;br /&gt;    else&lt;br /&gt;        raise (new System.ApplicationException())&lt;br /&gt;with&lt;br /&gt;| :? System.ApplicationException -&amp;gt;&lt;br /&gt;    print_endline &amp;quot;A second that was not a multiple of 3&amp;quot;&lt;br /&gt;| _ -&amp;gt;&lt;br /&gt;    print_endline &amp;quot;A second that was a multiple 3&amp;quot;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;|&amp;gt; 操作符（Pipe-Forward Operator）&lt;/strong&gt;

  &lt;br /&gt;在应用.NET类库时，&amp;#8220;|&amp;gt;&amp;#8221;操作符很有用，因为它可以帮助编译器正确地推导出函数参数的类型。它的定义很简单：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let (|&amp;gt;) x f = f x&lt;/pre&gt;

&lt;p&gt;类型信息为：&lt;/p&gt;

&lt;pre&gt;Tips&lt;br /&gt;&amp;#39;a -&amp;gt; (&amp;#39;a -&amp;gt; &amp;#39;b) -&amp;gt; &amp;#39;b&lt;/pre&gt;

&lt;p&gt;可以这么来理解：x的类型为&amp;#39;a，函数f接受&amp;#39;a类型的参数，返回类型为&amp;#39;b，操作符的结果就是将x传递给f后所求得的值。除了这样将参数&amp;#8220;转交&amp;#8221;外，&amp;#8220;|&amp;gt;&amp;#8221;更重要的作用在于帮助编译器进行类型推导：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;open System&lt;br /&gt;let dateList = [ new DateTime(1999, 9, 18);&lt;br /&gt;    new DateTime(2000, 9, 19);&lt;br /&gt;    new DateTime(2001, 9, 20) ]&lt;br /&gt;    &lt;br /&gt;List.iter (fun d -&amp;gt; print_int d.Year) dateList&lt;/pre&gt;

&lt;p&gt;此时编译器会报告错误，因为它不能推导出d的类型（这个让我感到有点奇怪，iter函数的类型为(a&amp;#8217; -&amp;gt; unit) -&amp;gt; a&amp;#8217; list -&amp;gt; unit，它能推导出dateList的类型，却不能得出d的类型）。此时使用&amp;#8220;|&amp;gt;&amp;#8221;就没问题了，因为我们显式地告诉编译器d的类型：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;dateList |&amp;gt; List.iter (fun d -&amp;gt; print_int d.Year)&lt;/pre&gt;

&lt;p&gt;要了解事情的端倪，我们最好再来看第二个例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type fsDate = { year : int; month : int; day : int }&lt;br /&gt;let fsDateList = &lt;br /&gt;    [ { year = 1999; month = 12; day = 31 }&lt;br /&gt;      { year = 2000; month = 12; day = 31 }&lt;br /&gt;      { year = 2001; month = 12; day = 31 } ]&lt;br /&gt;      &lt;br /&gt;List.iter (fun d -&amp;gt; print_int d.year) fsDateList&lt;br /&gt;fsDateList |&amp;gt; List.iter (fun d -&amp;gt; print_int d.year)&lt;/pre&gt;

&lt;p&gt;这段代码不会有编译错误，虽然看起来跟前一个例子很像，其主要区别在于fsDate是F#中的自定义类型，DateTime则是非F#类库中的类型。我们可以得出结论，&lt;strong&gt;不管是外部的.NET类型还是F#类型，&amp;#8220;|&amp;gt;&amp;#8221;都可使用，而F#的自动类型推导最好用在F#类型上&lt;/strong&gt;。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let methods = System.AppDomain.CurrentDomain.GetAssemblies()&lt;br /&gt;            |&amp;gt; List.of_array&lt;br /&gt;            |&amp;gt; List.map (fun assm -&amp;gt; assm.GetTypes())&lt;br /&gt;            |&amp;gt; Array.concat&lt;br /&gt;            |&amp;gt; List.of_array&lt;br /&gt;            |&amp;gt; List.map (fun t -&amp;gt; t.GetMethods())&lt;br /&gt;            |&amp;gt; Array.concat&lt;br /&gt;            &lt;br /&gt;print_any methods&lt;/pre&gt;

&lt;p&gt;&amp;#8220;|&amp;gt;&amp;#8221;操作符还可用于串联多个函数调用，每次函数调用都将返回值传给下一个函数。
  &lt;br /&gt;&lt;strong&gt;小结&lt;/strong&gt;

  &lt;br /&gt;走马观花，这一站的风景看得差不多了，命令式编程的核心部分也介绍完毕。有了函数式编程和命令式编程的知识，我们应该有信心解决大部分问题了。使用F#，我们可以选择合适的编程范式，而不是囿于特定的一种范式。下一站，我们将看到第三种主要的编程范式&amp;#8212;&amp;#8212;面向对象编程。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：本文中的代码均在F# 1.9.4.17版本下编写，在F# CTP 1.9.6.0版本下可能不能通过编译。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面向对象编程概述（OOP）&lt;/strong&gt;

  &lt;br /&gt;面向对象编程是当今最流行的编程范式，看看TIOBE &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;2008年9月的编程语言排行榜&lt;/a&gt;就很清楚了：

  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_36.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_17.png" width="562" height="332" /&gt;&lt;/a&gt; 

  &lt;br /&gt;在这些主流语言中，除了C，都或多或少地提供对OOP的支持，而Java和C#更是纯粹的面向对象编程语言，C还有一个子集&amp;#8212;&amp;#8212;Objective-C。值得一提的是Delphi的强势回归。下图则是各个编程范式的占有率：

  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_34.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_16.png" width="465" height="120" /&gt;&lt;/a&gt; 

  &lt;br /&gt;&lt;strong&gt;OOP编程范式是指使用&amp;#8220;对象&amp;#8221;及&amp;#8220;对象&amp;#8221;之间的交互来设计应用程序&lt;/strong&gt;。OOP的基本概念包括类，对象，实例，方法，消息传递，继承，抽象，封装，多态和解耦（Decoupling）等。&amp;#8220;一切皆是对象&amp;#8221;这句话曾盛极一时，它也衍生出了像设计模式这样的重要理念。关于面向对象编程，需要很多本书来讲述，我这里只想说OOP只是设计方式的一种，计算机要解决的问题包罗万象，面对不同的问题，我们也要选择不同的范式，没必要所有问题都要往OO上靠。要了解OOP的更多内容，可以看&lt;a href="http://en.wikipedia.org/wiki/Object-oriented_programming"&gt;这里&lt;/a&gt;。

  &lt;br /&gt;面向对象编程是F#支持的第三种主要范式。我在这里将对其中的基本概念逐一介绍。

  &lt;br /&gt;&lt;strong&gt;类型转换（Casting）&lt;/strong&gt;

  &lt;br /&gt;在采用面向对象编程时，我们会面对一个类型的层次结构，在F#中，这个层次结构始自obj（即System.Object）。转换是指改变值的静态类型，可能是&lt;strong&gt;向上转换&lt;/strong&gt;（upcast），将类型向着基类的方向移动，也可能是&lt;strong&gt;向下转换&lt;/strong&gt;（downcast），将类型向着派生类的方向移动。

  &lt;br /&gt;向上转换是安全的，编译器总能够了解一个类型的所有基类。它的操作符是&amp;#8220;:&amp;gt;&amp;#8221;。下面的代码将string值转换为obj。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;let myStr = &amp;quot;A string value.&amp;quot;&lt;br /&gt;let myObj = (myStr :&amp;gt; obj)&lt;/pre&gt;

&lt;p&gt;向上转换的一个典型应用场景是在定义集合时。如果不使用向上转换，编译器会自动将集合的类型推导为第一个元素的类型，如果其它元素的类型与之不同，就会发生编译错误。我们不得不显式地进行类型转换：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;let myCtrls = &lt;br /&gt;    [| (new Button() :&amp;gt; Control);&lt;br /&gt;       (new TextBox() :&amp;gt; Control);&lt;br /&gt;       (new Label() :&amp;gt; Control) |]&lt;/pre&gt;

&lt;p&gt;我们知道在.NET中有值类型和引用类型之分，在&lt;strong&gt;对值类型进行向上转换时会自动对其装箱&lt;/strong&gt;。

  &lt;br /&gt;向下转换将值的静态类型转换为它的一个派生类，其操作符是&amp;#8220;:?&amp;gt;&amp;#8221;。这个就没那么安全了，因为编译器没法确定一个类的实例是否与其派生类兼容，如果不兼容（不能转换），程序运行时会抛出一个InvalidCastException。所以使用时要小心一点。看代码吧：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let moreCtrls = &lt;br /&gt;    [| (new Button() :&amp;gt; Control);&lt;br /&gt;       (new TextBox() :&amp;gt; Control) |]&lt;br /&gt;       &lt;br /&gt;let control = &lt;br /&gt;    let temp = moreCtrls.[0]&lt;br /&gt;    temp.Text &amp;lt;- &amp;quot;Click me&amp;quot;&lt;br /&gt;    temp&lt;br /&gt;    &lt;br /&gt;let button = &lt;br /&gt;    let temp = (control :?&amp;gt; Button)&lt;br /&gt;    temp.DoubleClick.Add(fun e -&amp;gt; MessageBox.Show(&amp;quot;Hey&amp;quot;) |&amp;gt; ignore)&lt;br /&gt;    temp&lt;/pre&gt;

&lt;p&gt;如果你担心转换的安全性，可以采用模式匹配来代替向下转换。
  &lt;br /&gt;&lt;strong&gt;类型测试 &lt;/strong&gt;

  &lt;br /&gt;与类型转换相近的概念是类型测试。比如一个窗体类，有时我们会循环它的所有控件，并对Button和TextBox采取不同的处理，这时就需要判断控件的类型。看个简单的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let anotherObj = (&amp;quot;Another string value.&amp;quot; :&amp;gt; obj)&lt;br /&gt;&lt;br /&gt;if (anotherObj :? string) then&lt;br /&gt;    print_endline &amp;quot;This object is a string.&amp;quot;&lt;br /&gt;else&lt;br /&gt;    print_endline &amp;quot;This object is not a string.&amp;quot;&lt;/pre&gt;

&lt;p&gt;类型转换操作符:&amp;gt;/:?&amp;gt;和类型测试操作符:?，类似于C#的as和is。
  &lt;br /&gt;&lt;strong&gt;对派生类使用类型标注&lt;/strong&gt;

  &lt;br /&gt;函数式编程提到过，可以对标识符（比如参数）使用&lt;strong&gt;类型标注&lt;/strong&gt;（Type Annotation），以限定它的类型。但它也有些&amp;#8220;死板&amp;#8221;，它不考虑类型的继承层次。如果参数类型标注为Control类型，那就不能传入Button类型的值。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;&lt;br /&gt;let showForm(form : Form) =&lt;br /&gt;    form.Show()&lt;br /&gt;    &lt;br /&gt;// PrintPreviewDialog定义在BCL中，派生自Form类&lt;br /&gt;let myForm = new PrintPreviewDialog()&lt;br /&gt;&lt;br /&gt;showForm myForm&lt;/pre&gt;

&lt;p&gt;编译器会报告错误：&amp;#8220;This expression has type PrintPreviewDialog but is here used with type&amp;#160; Form&amp;#8221;。当然，我们可以在传入参数时将值转换为所标注的类：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;showForm(myForm :&amp;gt; Form)&lt;/pre&gt;

&lt;p&gt;这样是可以工作，但毕竟不太漂亮。我们还可以这么做：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let showFormRevised(form : #Form) =&lt;br /&gt;    form.Show()&lt;br /&gt;   &lt;br /&gt;let myForm = new PrintPreviewDialog()&lt;br /&gt;&lt;br /&gt;showFormRevised myForm&lt;/pre&gt;

&lt;p&gt;&amp;#8220;#&amp;#8221;让代码更优雅，可以避免很多转换。现在重写一下本文开始处的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let myCtrls = &lt;br /&gt;    [| (new Button() :&amp;gt; Control);&lt;br /&gt;       (new TextBox() :&amp;gt; Control);&lt;br /&gt;       (new Label() :&amp;gt; Control) |]&lt;br /&gt;       &lt;br /&gt;let uc(c : #Control) = c :&amp;gt; Control&lt;br /&gt;let myConciseCtrls =&lt;br /&gt;    [| uc(new Button()); uc(new TextBox()); uc(new Label()) |]&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;使用记录类型模拟对象&lt;/strong&gt;

  &lt;br /&gt;记录类型有自己的字段，而字段值可以是函数，这样我们可以使用这个特性来模拟对象的方法。事实上，在函数式编程语言拥有OO结构之前人们就是这样做的。而且，在定义记录类型时，我们仅需要给出函数的类型而无须实现，这样函数的实现就很容易进行替换（而在OOP中，往往需要定义派生类来覆盖基类的实现）。

  &lt;br /&gt;下面用经典的Shape例子来演示这个过程。&lt;/p&gt;

&lt;pre&gt;F# Code - 使用记录类型模拟对象&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;open System.Drawing&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;&lt;br /&gt;// 定义两个方法，此时仅仅声明函数的类型&lt;br /&gt;type Shape =&lt;br /&gt;    { reposition : Point -&amp;gt; unit;&lt;br /&gt;      draw : Graphics -&amp;gt; unit }&lt;br /&gt;&lt;br /&gt;// 创建一个Shape实例，并为它实现了两个方法  &lt;br /&gt;let makeShape initPos draw =&lt;br /&gt;    let currPos = ref initPos in&lt;br /&gt;    {   reposition = (fun newPos -&amp;gt; currPos := newPos);&lt;br /&gt;        draw = (fun g -&amp;gt; draw !currPos g);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;// 创建一个circle（Shape）实例，它替换了前面draw的实现&lt;br /&gt;let makeCircle initPos diam =&lt;br /&gt;    makeShape initPos (fun pos g -&amp;gt;&lt;br /&gt;        g.DrawEllipse(Pens.Blue, pos.X, pos.Y, diam, diam))&lt;br /&gt;    &lt;br /&gt;// 创建一个square（Shape）实例，它替换了前面draw的实现   &lt;br /&gt;let makeSquare initPos size =&lt;br /&gt;    makeShape initPos (fun pos g -&amp;gt;&lt;br /&gt;        g.DrawRectangle(Pens.Blue, pos.X, pos.Y, size, size))&lt;br /&gt;&lt;br /&gt;let getPoint(x, y) = new Point(x, y)&lt;br /&gt;&lt;br /&gt;let shapes =&lt;br /&gt;    [ makeCircle (getPoint(10, 10)) 20; makeSquare (getPoint(30, 30)) 20; ]&lt;br /&gt;    &lt;br /&gt;let mainForm =&lt;br /&gt;    let form = new Form()&lt;br /&gt;    let rand = new Random()&lt;br /&gt;    form.Paint.Add(fun e -&amp;gt;&lt;br /&gt;        shapes |&amp;gt; List.iter(fun s -&amp;gt; s.draw e.Graphics)&lt;br /&gt;    )&lt;br /&gt;    form.Click.Add(fun e -&amp;gt;&lt;br /&gt;        shapes |&amp;gt; List.iter(fun s -&amp;gt; &lt;br /&gt;            s.reposition(new Point(rand.Next(form.Width), rand.Next(form.Height)));&lt;br /&gt;            form.Invalidate())&lt;br /&gt;    )&lt;br /&gt;    form&lt;br /&gt;&lt;br /&gt;[&amp;lt;STAThread&amp;gt;]&lt;br /&gt;do Application.Run(mainForm)&lt;/pre&gt;

&lt;p&gt;这段代码将在窗体上画出一个圆和正方形。makeShape用于返回一个通用的Shape，makeCircle和makeSquare则用于返回两种特定的Shape。最后在Form的Paint事件中画出这两个Shape。这样我们可以快速创建不同功能的记录类型，却不用创建额外的类型。这与我们在C#中的惯用方式不同，下一节中将介绍一种更为自然的方式：向F#类型中添加成员。
  &lt;br /&gt;&lt;strong&gt;向F#类型添加成员 &lt;/strong&gt;

  &lt;br /&gt;F#中的类型包括记录（Record）和Union类型，两者均可以添加成员。在&lt;a href="http://www.cnblogs.com/anderslly/archive/2008/09/06/fs-adventure-fp-part-three.html"&gt;函数式编程（下）&lt;/a&gt;中，我们看到了如何定义类型，要为之添加成员需要在字段定义的末尾处进行。看下面的例子：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;// 包含两个字段，一个方法&lt;br /&gt;type Point =&lt;br /&gt;    {   mutable top : int;&lt;br /&gt;        mutable left : int }&lt;br /&gt;    with&lt;br /&gt;        member this.Swap() =&lt;br /&gt;            let temp = this.top&lt;br /&gt;            this.top &amp;lt;- this.left&lt;br /&gt;            this.left &amp;lt;- temp&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;let printAnyNewline x =&lt;br /&gt;    print_any x&lt;br /&gt;    print_newline()&lt;br /&gt;&lt;br /&gt;// 定义Point类的实例&lt;br /&gt;let p = { top = 30; left = 40; }&lt;br /&gt;&lt;br /&gt;let main() =&lt;br /&gt;    printAnyNewline p&lt;br /&gt;    p.Swap()&lt;br /&gt;    printAnyNewline p&lt;br /&gt;    &lt;br /&gt;main()&lt;/pre&gt;

&lt;p&gt;输出结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;{ top = 30;&lt;br /&gt; left = 40;}&lt;br /&gt;{ top = 40;&lt;br /&gt; left = 30;}&lt;/pre&gt;

&lt;p&gt;看看Point的定义，前半部分是字段们的定义，这个跟前面的一样，后半部分是一个with&amp;#8230;end代码块，这里通过member关键字定义了方法Swap。注意Swap前面的this参数，它表示持有该方法的类实例，即Swap通过这个实例被调用。一些语言都有特定的关键字来表示这里的this，如C#中的this和VB.NET中的Me，但F#要求你选择该参数的名字，该名字没有限制，你完全可以用x代替这里的this。只是如果用惯了C#，this看起来会更亲切。
  &lt;br /&gt;Union类型也可以有成员方法。定义方式与记录类型相同。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type DrinkAmount =&lt;br /&gt;    | Coffee of int&lt;br /&gt;    | Tea of int&lt;br /&gt;    | Water of int&lt;br /&gt;    with&lt;br /&gt;        override this.ToString() =&lt;br /&gt;            match this with&lt;br /&gt;            | Coffee x -&amp;gt; Printf.sprintf &amp;quot;Coffee: %i&amp;quot; x&lt;br /&gt;            | Tea x -&amp;gt; Printf.sprintf &amp;quot;Tea: %i&amp;quot; x&lt;br /&gt;            | Water x -&amp;gt; Printf.sprintf &amp;quot;Water: %i&amp;quot; x&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;let t = Tea 2&lt;br /&gt;print_endline (t.ToString())&lt;/pre&gt;

&lt;p&gt;输出结果为：&lt;/p&gt;

&lt;pre&gt;Tea: 2&lt;/pre&gt;

&lt;p&gt;这里为类型添加了成员方法ToString，不过使用的是override而不是member，这意味着覆盖了基类（obj）的ToString实现。
  &lt;br /&gt;&lt;strong&gt;小结 &lt;/strong&gt;

  &lt;br /&gt;首先对OOP做了简单介绍，然后逐一介绍了类型转换、类型测试、对派生类使用类型标注、使用记录类型模拟对象、向F#类型添加成员方法，通过这些我们能将值和函数封装在类型内部。在下一篇中将介绍接口和继承等相关语言结构。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：本文中的代码均在F# 1.9.4.17版本下编写，在F# CTP 1.9.6.0版本下可能不能通过编译。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;对象表达式（Object Expressions）&lt;/strong&gt;

  &lt;br /&gt;F#中的OOP语法很简洁，而对象表达式则正是这种简洁性的核心所在。通过对象表达式，我们可以创建抽象类或接口的轻量级实现，也可以对一个具体的类进行继承。换言之，可以在实现抽象类或接口，或者继承具体类的同时创建新类型的一个实例。下面来看如何对泛型接口IComparer&amp;lt;&amp;#8217;T&amp;gt;应用对象表达式。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;open System.Collections.Generic&lt;br /&gt;&lt;br /&gt;let revStringComparer =&lt;br /&gt;    { new IComparer&amp;lt;string&amp;gt;&lt;br /&gt;        with&lt;br /&gt;            Compare(s1, s2) =&lt;br /&gt;                let rev (s : string) =&lt;br /&gt;                    new string(Array.rev(s.ToCharArray()))&lt;br /&gt;                let reversed = rev s1&lt;br /&gt;                reversed.CompareTo(rev s2)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;let winners = [| &amp;quot;Sandie Shaw&amp;quot;; &amp;quot;Bucks Fizz&amp;quot;; &amp;quot;Dana International&amp;quot;; &amp;quot;Abba&amp;quot; |]&lt;br /&gt;&lt;br /&gt;print_any winners&lt;br /&gt;print_newline()&lt;br /&gt;Array.Sort(winners, revStringComparer)&lt;br /&gt;print_any winners&lt;/pre&gt;

&lt;p&gt;运行结果为&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;[|&amp;quot;Sandie Shaw&amp;quot;; &amp;quot;Bucks Fizz&amp;quot;; &amp;quot;Dana International&amp;quot;; &amp;quot;Abba&amp;quot;|]&lt;br /&gt;[|&amp;quot;Abba&amp;quot;; &amp;quot;Dana International&amp;quot;; &amp;quot;Sandie Shaw&amp;quot;; &amp;quot;Bucks Fizz&amp;quot;|]&lt;/pre&gt;

&lt;p&gt;这里演示了实现IComparer的过程，该接口有一个方法Compare，它接受两个参数并通过返回值来表示参数比较的结果。它是泛型接口，这里的类型参数为string，可以在标识符revStringComparer定义的第二行看到。从标识符的名字也可以了解到，它是将参数颠倒后进行比较，运行结果的第二行印证了这一点。可以看到&amp;#8220;&lt;strong&gt;在实现接口的同时返回一个实例&lt;/strong&gt;&amp;#8221;。

  &lt;br /&gt;看看多重继承的情况。在C#中，一个类不能继承多个类，却可以同时实现多个接口，F#也是一样的。要注意的是，如果同时继承类并实现接口，须将类的部分房子最前面；而且必须在第一个类/接口定义完毕之后才能开始第二个接口的实现。&lt;/p&gt;

&lt;pre&gt;多重继承的例子&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;open System.Drawing&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;&lt;br /&gt;let makeNumberControl(n: int) =&lt;br /&gt;    { new Control(Tag = n, Width = 32, Height = 16) &lt;br /&gt;      with&lt;br /&gt;          override x.OnPaint(e) =&lt;br /&gt;              let font = new Font(FontFamily.Families.[1], 12.0F)&lt;br /&gt;              e.Graphics.DrawString(n.ToString(), font, Brushes.Black, &lt;br /&gt;                  new PointF(0.0F, 0.0F))&lt;br /&gt;            &lt;br /&gt;      interface IComparable &lt;br /&gt;      with&lt;br /&gt;          CompareTo(other) =&lt;br /&gt;              let otherCtrl = other :?&amp;gt; Control in&lt;br /&gt;              let n1 = otherCtrl.Tag :?&amp;gt; int in&lt;br /&gt;              n.CompareTo(n1) }&lt;br /&gt;    &lt;br /&gt;let numberCtrls =&lt;br /&gt;    let temp = new ResizeArray&amp;lt;Control&amp;gt;()&lt;br /&gt;    let random = new Random()&lt;br /&gt;    for index = 1 to 10 do&lt;br /&gt;        temp.Add(makeNumberControl(random.Next(100)))&lt;br /&gt;    temp.Sort()&lt;br /&gt;    let height = ref 0&lt;br /&gt;    temp |&amp;gt; Seq.iter&lt;br /&gt;        (fun c -&amp;gt;&lt;br /&gt;            c.Top &amp;lt;- !height&lt;br /&gt;            height := c.Height + !height)&lt;br /&gt;    temp.ToArray()&lt;br /&gt;    &lt;br /&gt;let myForm =&lt;br /&gt;    let temp = new Form() in&lt;br /&gt;    temp.Controls.AddRange(numberCtrls);&lt;br /&gt;    temp&lt;br /&gt;    &lt;br /&gt;[&amp;lt;STAThread&amp;gt;]&lt;br /&gt;do Application.Run(myForm)&lt;/pre&gt;

&lt;p&gt;在对象表达式makeNumberControl中，它继承了Control类，同时也实现了IComparable接口。这里可以看到，在CompareTo方法中根据控件的Tag值进行比较，在调用Sort方法（ResizeArray即泛型类List&amp;lt;&amp;#8217;T&amp;gt;）时会根据Compare方法对控件进行排序。排序完成后，依次呈现这些控件，如下图：
  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_38.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_18.png" width="244" height="244" /&gt;&lt;/a&gt; 

  &lt;br /&gt;对象表达式是一种强大的机制，可以帮助我们&lt;strong&gt;快速而简洁地将非F#库中的对象引入F#代码&lt;/strong&gt;。它的&lt;strong&gt;缺点则是没法添加额外的属性或方法&lt;/strong&gt;。这也是在前面的例子中为何使用Tag属性来存放n的值。

  &lt;br /&gt;&lt;strong&gt;定义接口 &lt;/strong&gt;

  &lt;br /&gt;接口仅包含抽象的方法和属性。它为所有实现它的类定义了一份&amp;#8220;契约&amp;#8221;。F#中接口的概念与C#中的相同，在此不再赘述。如：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type MyInterface = interface&lt;br /&gt;    abstract ChangeState : int -&amp;gt; unit&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;实现接口 &lt;/strong&gt;

  &lt;br /&gt;实现接口的语法也很简单。仍以上面的接口为例：&lt;/p&gt;

&lt;pre&gt;F# Code - 实现接口&lt;br /&gt;type MyImpl = class&lt;br /&gt;    val mutable state : int&lt;br /&gt;    new() = { state = 0 }&lt;br /&gt;    interface MyInterface with&lt;br /&gt;        member x.ChangeState y = x.state &amp;lt;- y&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let impl = new MyImpl()&lt;br /&gt;let inter = impl :&amp;gt; MyInterface&lt;br /&gt;&lt;br /&gt;let printIntAndNewLine i =&lt;br /&gt;    print_int i&lt;br /&gt;    print_newline()&lt;br /&gt;&lt;br /&gt;let main() =&lt;br /&gt;    inter.ChangeState 1&lt;br /&gt;    printIntAndNewLine impl.state&lt;br /&gt;    inter.ChangeState 2&lt;br /&gt;    printIntAndNewLine impl.state&lt;br /&gt;&lt;br /&gt;main()&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;1&lt;br /&gt;2&lt;/pre&gt;

&lt;p&gt;不知你有没有注意到，在调用ChangeState方法前，我们先将impl转换为了MyInterface类型，否则不能调用。这是因为接口在F#中是显式实现的，如果希望不经转换就可以直接调用接口的方法，只能在类中在显式地添加这个方法:-(
  &lt;br /&gt;&lt;strong&gt;类、字段和显式的构造函数&lt;/strong&gt;

  &lt;br /&gt;前面我们主要还是使用非F#库中的类，现在来看看如何定义自己的类。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;type EmptyClass = class&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let emptyItem = new EmptyClass()&lt;/pre&gt;

&lt;p&gt;嗯，很明显，这里试图定义一个类，然后创建它的一个实例。不过编译器不允许你这么做，它会告诉你：&amp;#8220;error FS0191: No constructors are available for the type &amp;#39;EmptyClass&amp;#39;&amp;#8221;。没有构造函数？如果你是C#程序员就会觉得奇怪了。事实上，&lt;strong&gt;F#没有提供默认的构造函数&lt;/strong&gt;这种机制，我们必须得手工添加一个，&lt;strong&gt;构造函数的名字总是为new&lt;/strong&gt;。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type EmptyClass = class&lt;br /&gt;    new() = {}&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;另外，默认的构造函数容易使得字段不能正确地初始化，会给程序带来隐患，而在&lt;strong&gt;F#中的构造函数必须初始化所有字段&lt;/strong&gt;。使用val关键字定义字段，在下面的类MyFile中，它拥有两个字段，path和innerFile，两个字段在构造函数内进行初始化。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;#light&lt;br /&gt;open System.IO&lt;br /&gt;&lt;br /&gt;type MyFile = class&lt;br /&gt;    val path : string&lt;br /&gt;    val innerFile : FileInfo&lt;br /&gt;    new() = new MyFile(&amp;quot;default.txt&amp;quot;)&lt;br /&gt;    new(p) =&lt;br /&gt;        { path = p; &lt;br /&gt;          innerFile = new FileInfo(p) }&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;我们还可以看到，这个类有两个构造函数，也就是说&lt;strong&gt;构造函数可以重载&lt;/strong&gt;。观察构造函数new(p)，它有一部分在{}内，这个代码块称为构造函数的初始化块，在这里唯一能做的事情就是初始化字段。如果想做更多的事情，就要在后面加then添加其它代码：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type MyFile2 = class&lt;br /&gt;    val path : string&lt;br /&gt;    val innerFile : FileInfo&lt;br /&gt;    new(p) as x =&lt;br /&gt;        { path = p;&lt;br /&gt;          innerFile = new FileInfo(p) }&lt;br /&gt;        then&lt;br /&gt;        if not x.innerFile.Exists then&lt;br /&gt;            let textFile = x.innerFile.CreateText()&lt;br /&gt;            textFile.Dispose()&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;new(p)后面加了as x，这样就可以在后面的代码中引用当前的对象了。then后面的代码首先检查文件是否存在，如果不存在就创建一个新文件。
  &lt;br /&gt;&lt;strong&gt;注意&lt;/strong&gt;：上面两个类MyFile和MyFile2中的&lt;strong&gt;字段都是只读的&lt;/strong&gt;，如果需要修改它们，可以在字段名字前面添加关键字&lt;strong&gt;mutable&lt;/strong&gt;，如val mutable innerFile；同时&lt;strong&gt;它们的访问修饰符都是public&lt;/strong&gt;，在下一篇文章将介绍如何在类中定义属性。

  &lt;br /&gt;&lt;strong&gt;思考&lt;/strong&gt;：在函数式编程中，曾介绍过自定义的记录类型，比如&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;type couple = { him : string; her : string }&lt;/pre&gt;

&lt;p&gt;那么这里的couple类和上面的MyFile类主要有哪些区别呢？请出我们的老朋友.NET Reflector来吧。在Reflector中打开编译过的F#程序集可以看到，couple的类型定义为：&lt;/p&gt;

&lt;pre&gt;Type Infomation&lt;br /&gt;public sealed class couple : IStructuralHash, IComparable&lt;/pre&gt;

&lt;p&gt;这是一个&lt;strong&gt;sealed类&lt;/strong&gt;，这意味着无法继承它，其中的her和him都是只读属性。

  &lt;br /&gt;而MyFile的定义则是：&lt;/p&gt;

&lt;pre&gt;Type Infomation&lt;br /&gt;public class MyFile&lt;/pre&gt;

&lt;p&gt;这个就跟C#中常规类的定义一致了，其中的path和innerFile都是只读属性。
  &lt;br /&gt;&lt;strong&gt;隐式的类构造（Implicit Class Construction） &lt;/strong&gt;

  &lt;br /&gt;除了上面的显式构造函数，&lt;strong&gt;F#还支持隐式的类构造语法&lt;/strong&gt;，&lt;strong&gt;这样的语法更为紧凑&lt;/strong&gt;。它允许在定义类的成员前执行一系列的let值绑定语句，&lt;strong&gt;这些绑定属于类的私有部分&lt;/strong&gt;。&lt;/p&gt;

&lt;pre&gt;F# Code - 隐式的类构造&lt;br /&gt;#light&lt;br /&gt;open System.IO&lt;br /&gt;&lt;br /&gt;type MyOtherFile(path) = class&lt;br /&gt;    let innerFile = new FileInfo(path)&lt;br /&gt;    member x.InnerFile = innerFile&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;我觉得对于前面的（显式的类构造）MyFile类定义，这里的MyOtherFile类当然更为紧凑，看起来在定义类的同时就定义了构造函数，随后马上初始化了字段，不过这里的innerFile已经是私有的了，所以再添加一个属性InnerFile来公开innerFile字段。
  &lt;br /&gt;隐式的类构造要比等价的显式类构造代码少很多，但是有时必须要用显式的类构造，比如编写拥有多个构造函数的类的时候。

  &lt;br /&gt;&lt;strong&gt;小结&lt;/strong&gt;

  &lt;br /&gt;本文首先介绍了强大的对象表达式机制，通过它，我们可以快速地创建抽象类或接口的轻量级实现；接下来是定义和实现接口；最后介绍了如何创建和实例化一个类，在创建类实例的时候，我们既可以采用显式的构造函数，也可以采用更为紧凑的&amp;#8220;隐式的类构造&amp;#8221;机制。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：本文中的代码均在F# 1.9.4.17版本下编写，在F# CTP 1.9.6.0版本下可能不能通过编译。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;类的继承&lt;/strong&gt;

  &lt;br /&gt;在前面面向对象介绍过的对象表达式中，已经涉及到了类的继承，我们可以覆盖类的成员实现，然后创建新类的实例。这一节里，我们来看看常规的继承机制，熟悉C#的开发人员会感到更亲切。&lt;/p&gt;

&lt;pre&gt;F# Code - 类的继承&lt;br /&gt;#light&lt;br /&gt;type Base = class&lt;br /&gt;    val state : int&lt;br /&gt;    new() = { state = 0}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;type Sub = class&lt;br /&gt;    inherit Base&lt;br /&gt;    val otherState : int&lt;br /&gt;    new() = { otherState = 1 }&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let myObj = new Sub()&lt;br /&gt;&lt;br /&gt;printfn &amp;quot;myObj.state = %i, myObj.otherState = %i&amp;quot;&lt;br /&gt;    myObj.state&lt;br /&gt;    myObj.otherState&lt;br /&gt;    &lt;br /&gt;System.Console.Read()&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;myObj.state = 0, myObj.otherState = 1&lt;/pre&gt;

&lt;p&gt;这里Base类为基类，有一个字段state，Sub继承了它，并有一个新字段otherState，下面的代码可以看到，此时Sub类继承了Base类的state字段。需要注意的是，这里的&lt;strong&gt;Base必须要有一个无参的构造函数，否则不能通过编译&lt;/strong&gt;。其原因是，跟C#一样，在初始化派生类时会调用基类的构造函数，而F#中类没有默认的构造函数，所以必须显式添加构造函数。而如果基类的构造函数带有参数的话，派生类的构造函数写法也有所不同。&lt;/p&gt;

&lt;pre&gt;F# Code - 基类具有含参的构造函数&lt;br /&gt;#light&lt;br /&gt;type Base = class&lt;br /&gt;    val state : int&lt;br /&gt;    new(st) = &lt;br /&gt;        { state = st}&lt;br /&gt;        then&lt;br /&gt;        printfn &amp;quot;Init base class&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;type Sub = class&lt;br /&gt;    inherit Base&lt;br /&gt;    val otherState : int&lt;br /&gt;    new() = &lt;br /&gt;        { inherit Base(0)&lt;br /&gt;          otherState = 1 }&lt;br /&gt;        then&lt;br /&gt;        printfn &amp;quot;Init sub class&amp;quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let myObj = new Sub()&lt;br /&gt;&lt;br /&gt;printfn &amp;quot;myObj.state = %i, myObj.otherState = %i&amp;quot;&lt;br /&gt;    myObj.state&lt;br /&gt;    myObj.otherState&lt;br /&gt;    &lt;br /&gt;System.Console.Read()&lt;/pre&gt;

&lt;p&gt;运行结果：&lt;/p&gt;

&lt;pre&gt;Init base class&lt;br /&gt;Init sub class&lt;br /&gt;myObj.state = 0, myObj.otherState = 1&lt;/pre&gt;

&lt;p&gt;这个结果说明确实调用了基类的构造函数。Inherit Base(0)则说明，我们必须选择正确的构造函数。
  &lt;br /&gt;&lt;strong&gt;类的方法 &lt;/strong&gt;

  &lt;br /&gt;定义方法时可以使用4个相关的关键字，即member、override、abstract、default。在C#中，类的方法大体上可分为三种情况。一是在基类中定义，派生类中不能覆盖的；二是在基类中定义，派生类可以覆盖的（使用virtual关键字）；三是抽象方法（或接口方法），派生类需要提供实现的（除非派生类也是抽象类或接口）。对于情况一，可以简单地使用member关键字；情况二，可同时使用abstract和default（或override），abstract说明该方法可以进行覆盖，default则提供了默认实现；情况三，可仅仅使用abstract，同时为类添加特性AbstractClass，说明该方法是抽象类的一个抽象方法，必须在派生类中提供实现。&lt;/p&gt;

&lt;pre&gt;F# Code - 类继承时的方法&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type Base = class&lt;br /&gt;    val mutable state: int&lt;br /&gt;    new() = { state = 0 }&lt;br /&gt;    member x.JiggleState y = x.state &amp;lt;- y&lt;br /&gt;    abstract WiggleState: int -&amp;gt; unit&lt;br /&gt;    default x.WiggleState y = x.state &amp;lt;- y + x.state&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;type Sub = class&lt;br /&gt;    inherit Base&lt;br /&gt;    new() = {}&lt;br /&gt;    override x.WiggleState y = x.state &amp;lt;- y &amp;amp;&amp;amp;&amp;amp; x.state&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let myBase = new Base()&lt;br /&gt;let mySub = new Sub()&lt;br /&gt;&lt;br /&gt;let test(c: #Base) =&lt;br /&gt;    c.JiggleState 1&lt;br /&gt;    print_int c.state&lt;br /&gt;    print_newline()&lt;br /&gt;    c.WiggleState 3&lt;br /&gt;    print_int c.state&lt;br /&gt;    print_newline()&lt;br /&gt;    &lt;br /&gt;print_endline &amp;quot;base class: &amp;quot;&lt;br /&gt;test myBase&lt;br /&gt;print_endline &amp;quot;sub class: &amp;quot;&lt;br /&gt;test mySub&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;base class: &lt;br /&gt;1&lt;br /&gt;4&lt;br /&gt;sub class: &lt;br /&gt;1&lt;br /&gt;1&lt;/pre&gt;

&lt;p&gt;可以看到JiggleState方法继承了Base的实现，而WiggleState则覆盖了Base的默认实现。
  &lt;br /&gt;&lt;strong&gt;访问基类的成员&lt;/strong&gt;

  &lt;br /&gt;如果你曾写过Page类的派生类，那么很可能写过base.OnLoad()这样的代码。&amp;#8220;base&amp;#8221;用来引用基类中的成员，在F#中稍有不同。就像没有this一样，base也是没有的，需要给它手工指定名称。&lt;/p&gt;

&lt;pre&gt;F# Code - 访问基类的成员&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;open System.Drawing&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;&lt;br /&gt;type RectangleForm(color) = class&lt;br /&gt;    inherit Form() as base&lt;br /&gt;    override x.OnPaint(e) = &lt;br /&gt;        e.Graphics.DrawRectangle(color, 10, 10,&lt;br /&gt;            x.Width - 30, x.Height - 50)&lt;br /&gt;        base.OnPaint(e)&lt;br /&gt;    override x.OnResize(e) =&lt;br /&gt;        x.Invalidate()&lt;br /&gt;        base.OnResize(e)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let form = new RectangleForm(Pens.Blue)&lt;br /&gt;&lt;br /&gt;[&amp;lt;STAThread&amp;gt;]&lt;br /&gt;do Application.Run(form)&lt;/pre&gt;

&lt;p&gt;这里定义Form类的派生类RectangleForm，注意在inherit后面的as base，这里的base就是给基类起的名字，这个名字是任意的。在覆盖OnPaint时就调用了基类的OnPaint方法。
  &lt;br /&gt;&lt;strong&gt;属性和索引器 &lt;/strong&gt;

  &lt;br /&gt;属性（Property）和索引器（Indexer）是.NET中重要的&amp;#8220;语法糖&amp;#8221;特性，它们使得我们的代码更为直观、简洁，而它们本质上是方法。&lt;/p&gt;

&lt;pre&gt;F# Code - 定义属性&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;&lt;br /&gt;type Propreties() = class&lt;br /&gt;    let mutable rand = new Random()&lt;br /&gt;    member x.MyProp&lt;br /&gt;        with get() = rand.Next()&lt;br /&gt;        and set y = rand &amp;lt;- new Random(y)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let prop = new Propreties()&lt;br /&gt;prop.MyProp &amp;lt;- 10&lt;br /&gt;printfn &amp;quot;%d&amp;quot; prop.MyProp&lt;br /&gt;printfn &amp;quot;%d&amp;quot; prop.MyProp&lt;/pre&gt;

&lt;p&gt;在Properties类中定义属性MyProp，这里我们可以看到熟悉的get/set变成了两个方法get/set，参数y就是C#中的value。
  &lt;br /&gt;索引器是一种特殊的属性（又称含参属性）。在C#中，索引器本质上是名为Item的方法。在F#中，我们也可以使用Item之外的名字。&lt;/p&gt;

&lt;pre&gt;F# Code - 定义索引器&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type Indexers(vals : string[]) = class&lt;br /&gt;    member x.Item&lt;br /&gt;        with get(i) = vals.[i]&lt;br /&gt;        and set(i, v) = vals.[i] &amp;lt;- v&lt;br /&gt;    member x.MyString&lt;br /&gt;        with get(i) = vals.[i]&lt;br /&gt;        and set(i, v) = vals.[i] &amp;lt;- v&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let indexer = new Indexers [| &amp;quot;One&amp;quot;; &amp;quot;Two&amp;quot;; &amp;quot;Three&amp;quot;; &amp;quot;Four&amp;quot; |]&lt;br /&gt;&lt;br /&gt;indexer.[0] &amp;lt;- &amp;quot;Five&amp;quot;&lt;br /&gt;indexer.Item(2) &amp;lt;- &amp;quot;Six&amp;quot;&lt;br /&gt;indexer.MyString(3) &amp;lt;- &amp;quot;Seven&amp;quot;&lt;br /&gt;print_endline indexer.[0]&lt;br /&gt;print_endline(indexer.Item(1))&lt;br /&gt;print_endline(indexer.MyString(2))&lt;br /&gt;print_endline(indexer.MyString(3))&lt;/pre&gt;

&lt;p&gt;这里的Indexers类定义了两个索引器：Item和MyString，通过Reflector可以看到，它们的签名相同，都是&amp;#8220;public string this[int i] { get; set; }&amp;#8221;，在C#中这是不允许的。C#中索引器的默认名称为Item，对于这里的Item来说，可以用两种方式访问它，而MyString就只有一种了。&lt;strong&gt;如果需要考虑同其它语言的兼容性，建议使用Item定义属性&lt;/strong&gt;。

  &lt;br /&gt;&lt;strong&gt;类的静态方法 &lt;/strong&gt;

  &lt;br /&gt;静态方法的定义是实例方法类似，不过要用到static关键字。访问静态方法时，不需要建立类的实例，可以通过类直接访问，如下面的ReverseString方法。&lt;/p&gt;

&lt;pre&gt;F# Code - 定义静态方法&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type MyClass = class&lt;br /&gt;    static member ReverseString(s: string) =&lt;br /&gt;        let chars = s.ToCharArray()&lt;br /&gt;        let reversedChars = Array.rev chars&lt;br /&gt;        new string(reversedChars)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;let myString = MyClass.ReverseString &amp;quot;dlrow olleH&amp;quot;&lt;br /&gt;print_string myString&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;img alt="" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" height="16" /&gt;&lt;img alt="" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" height="16" /&gt;Output&lt;br /&gt;Hello world&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;定义委托&lt;/strong&gt;

  &lt;br /&gt;在C#中，通过委托可以像&amp;#8220;值&amp;#8221;那样去处理方法。显然，在F#中不需要这样，因为函数本来就是当作值来看待的。但是考虑到与其它语言的交互，有时也需要定义委托。&lt;/p&gt;

&lt;pre&gt;F# Code - 定义委托&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type MyDelegate = delegate of int -&amp;gt; unit&lt;br /&gt;&lt;br /&gt;let myInst = new MyDelegate(fun i -&amp;gt; print_int i)&lt;br /&gt;let intList = [1; 2; 3]&lt;br /&gt;intList |&amp;gt; List.iter(fun i -&amp;gt; myInst.Invoke(i))&lt;/pre&gt;

&lt;p&gt;这里myInst是委托MyDelegate的一个实例，我们通过Invoke来调用它。运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;img alt="" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" height="16" /&gt;&lt;img alt="" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" height="16" /&gt;Output&lt;br /&gt;123&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;定义结构类型 &lt;/strong&gt;

  &lt;br /&gt;结构（struct）与类（class）的区别就是我们常说的值类型和引用类型的区别，在此不再赘述。下面定义的结构IpAddress用于表示IP地址。&lt;/p&gt;

&lt;pre&gt;F# Code - 定义结构类型 &lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type IpAddress = struct&lt;br /&gt;    val first: byte&lt;br /&gt;    val second: byte&lt;br /&gt;    val third: byte&lt;br /&gt;    val fourth: byte&lt;br /&gt;    new(first, second, third, fourth) =&lt;br /&gt;        { first = first;&lt;br /&gt;          second = second;&lt;br /&gt;          third = third;&lt;br /&gt;          fourth = fourth }&lt;br /&gt;    override x.ToString() =&lt;br /&gt;        Printf.sprintf &amp;quot;%O.%O.%O.%O&amp;quot; x.first x.second x.third x.fourth&lt;br /&gt;    member x.GetBytes() = x.first, x.second, x.third, x.fourth&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;定义枚举类型&lt;/strong&gt;

  &lt;br /&gt;枚举类型定义了一组符号名称和数值对，本质上讲，&lt;strong&gt;枚举类型就是定义了一组常数字段的结构&lt;/strong&gt;。F#中枚举的定义也是很简单的。&lt;/p&gt;

&lt;pre&gt;F# Code - 定义枚举类型&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;type Season =&lt;br /&gt;| Spring&lt;br /&gt;| Summer&lt;br /&gt;| Autumn&lt;br /&gt;| Winter&lt;/pre&gt;

&lt;p&gt;如果你希望定义位标记枚举，可以使用&lt;strong&gt;System.Flags&lt;/strong&gt;特性。

  &lt;br /&gt;&lt;strong&gt;小结&lt;/strong&gt;

  &lt;br /&gt;至此，F#中的面向对象编程范式介绍完毕，我们手中的F#也变得更为锐利。本文首先介绍了类的继承、类的方法（虚方法、抽象方法等）、访问基类等跟继承相关的概念；接着是类的属性和索引器、类的静态方法这些类的特殊成员；最后讨论了如何定义委托、结构类型、枚举类型等特殊类型。相信有了这些知识，我们完全可以使用F#代替C#来编写类库了。学习这些知识的过程，也给了我们一个从新的角度了解.NET Framework的机会。在学习了F#的三种主要编程范式之后，下一步该考虑如何在实战中应用它，比如如何组织规模较大的程序，如何建立UI，如何与其它.NET语言进行交互等等，在后续的随笔中将逐步介绍这些内容。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：本文中的代码均在F# 1.9.4.17版本下编写，在F# CTP 1.9.6.0版本下可能不能通过编译。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;关于函数式编程（Functional programming，FP）&lt;/b&gt;

  &lt;br /&gt;函数式编程（FP）是一种编程范式，它将计算过程视为函数运算，避免状态和数据的修改。与命令式编程相比，它更强调函数的运用。&amp;#955;运算构建了函数式编程的基础。重要的函数式编程语言包括Lisp、Scheme、Erlang、Haskell、ML、OCaml等，微软则在2005年引入了F#。

  &lt;br /&gt;此外，包括C/C++/C#/Python/Javascript等很多语言也提供了对FP的部分支持。由此我们可以得出一个结论，随着现实问题复杂度的增加，单一的编程范式很难满足需要了。我们需要对FP有更多的了解，问题是学习哪种语言呢？作为一个.NET程序员，我的答案是F#。使用F#，除了能借助FP的力量，最重要的一点是它&lt;b&gt;跟.NET平台的无缝兼容&lt;/b&gt;，它可以&lt;b&gt;轻松地与C#或VB.NET进行互操作&lt;/b&gt;，通过F#，我们手中的C#/VB.NET会变得更为强大。

  &lt;br /&gt;本文尝试通过F#对FP的一些重要特征和属性做些介绍，包括函数（一等公民、高阶函数、柯里化、匿名函数、闭包）、避免副作用（对状态和数据的修改）、递归、惰性求值、模式匹配；然后讨论了FP对代码结构的影响。像Continuation和Monad留在以后的随笔中介绍。希望能增加您对FP的认识。

  &lt;br /&gt;&lt;b&gt;函数是一等公民（First-class citizen） &lt;/b&gt;

  &lt;br /&gt;这里的citizen也可换作object/value/entity，所谓一等公民是指那些在程序中可以无限制（相比于同一语言中的其它对象）使用的对象。在编程语言中，&amp;#8220;函数是一等公民&amp;#8221;意味着它可以：

  &lt;br /&gt;1. 表示为匿名的文字值

  &lt;br /&gt;2. 存储于变量中

  &lt;br /&gt;3. 存储于数据结构中

  &lt;br /&gt;4. 作为函数的参数进行传递

  &lt;br /&gt;5. 作为函数的返回值

  &lt;br /&gt;6. 在运行时进行构造

  &lt;br /&gt;F#中的函数是一等公民，而在C#中，函数不是一等公民，比如我们不能把函数作为参数进行传递，也不能将其作为返回值，而对类则可以这么做。这种不同并不值得奇怪。如果我们把人类社会作为一个抽象来看，那么在它的不同实现中公民的等级也有所不同。在缅甸，和尚是一等公民，男人是二等公民，女人和尼姑是三等公民，人妖是四等公民，我们国家显然不是这样，但缅甸和中国的公民们&lt;b&gt;大部分&lt;/b&gt;都能活得好好的。&lt;/p&gt;

&lt;pre&gt;F# Code - First-class citizen&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;let makeDerivative f (deltaX: float) =&lt;br /&gt;    fun x -&amp;gt; (f(x + deltaX) - f(x)) / deltaX&lt;br /&gt;&lt;br /&gt;let cos = makeDerivative sin 0.000001&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;let writeLine input =&lt;br /&gt;    print_any input&lt;br /&gt;    Console.WriteLine()&lt;br /&gt;&lt;br /&gt;writeLine (cos 0.0) // ~= 1&lt;br /&gt;writeLine (cos(Math.PI / 2.0)) // ~= 0&lt;br /&gt;&lt;br /&gt;Console.Read()&lt;/pre&gt;

&lt;p&gt;在这个例子中，makeDerivative函数的第一个参数f是一个函数，它的返回值也是函数，返回的是一个匿名函数。
  &lt;br /&gt;&lt;b&gt;高阶函数（High-level function）&lt;/b&gt;

  &lt;br /&gt;&lt;b&gt;高阶函数是指那些可以接受其它函数为参数，或者把函数作为返回值的函数&lt;/b&gt;。上面的makeDerivative函数就是一个例子。高阶函数描述的是函数的数学概念，而&amp;#8220;函数是一等公民&amp;#8221;则是一个计算机科学的术语。

  &lt;br /&gt;还记得在高中数学中学过的&lt;b&gt;复合函数&lt;/b&gt;的概念吗？如果u(x) = x * 2，而y(u) = u + 3，那么y接受的&amp;#8220;参数&amp;#8221;是一个函数，而y本身也是一个函数。

  &lt;br /&gt;&lt;b&gt;函数柯里化（Currying） &lt;/b&gt;

  &lt;br /&gt;所谓柯里化，简单来说是指对于一个接受多个参数的函数，将第一个参数设为一个固定值，这样会得到一个新函数，新函数的参数是原函数第一个参数之外的函数。看下面简单的例子：&lt;/p&gt;

&lt;pre&gt;F# Code - 函数柯里化&lt;br /&gt;// val add : int -&amp;gt; int -&amp;gt; int&lt;br /&gt;let add a b = a + b&lt;br /&gt;// val increment : (int -&amp;gt; int)&lt;br /&gt;let increment = add 1&lt;/pre&gt;

&lt;p&gt;函数add接受两个参数，我们将第一个参数a设为固定值1，就得到新函数increment。
  &lt;br /&gt;&lt;b&gt;匿名函数（Anonymous function）&lt;/b&gt;

  &lt;br /&gt;顾名思义，我们定义了一个函数，也可以调用它，但没有为它设定一个名称，这样的函数就是匿名函数。在lambda运算中，所有函数都是匿名函数。

  &lt;br /&gt;在F#的列表操作中，会经常用到匿名函数。&lt;/p&gt;

&lt;pre&gt;F# Code - 匿名函数&lt;br /&gt;List.filter (fun i -&amp;gt; i % 2 = 0) [1 .. 20]&lt;/pre&gt;

&lt;p&gt;List.filter函数用于对列表进行过滤，其签名为：&lt;/p&gt;

&lt;pre&gt;Type Infomation&lt;br /&gt;val it : ((&amp;#39;a -&amp;gt; bool) -&amp;gt; &amp;#39;a list -&amp;gt; &amp;#39;a list)&lt;/pre&gt;

&lt;p&gt;第一个参数是返回bool值的函数，第二个参数是列表，返回值为使得第一个参数返回true的那些元素组成的新列表。本例中filter的第一个参数即匿名函数，使用关键字fun进行定义。本例中过滤后的新列表为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;[2; 4; 6; 8; 10; 12; 14; 16; 18; 20]&lt;/pre&gt;

&lt;p&gt;此外还可以使用function关键字定义匿名函数，第二种方式还可以使用模式匹配。
  &lt;br /&gt;&lt;b&gt;闭包（Closure）&lt;/b&gt;

  &lt;br /&gt;闭包是个比较抽象的概念，先来看下面的例子吧。&lt;/p&gt;

&lt;pre&gt;F# Code - 闭包（针对宿主函数的参数）&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;&lt;br /&gt;let makePower power =&lt;br /&gt;    let powerFn base = Math.Pow(base, power)&lt;br /&gt;    powerFn&lt;br /&gt;    &lt;br /&gt;let square = makePower 2.0&lt;br /&gt;Console.WriteLine(square(3.0))&lt;/pre&gt;

&lt;p&gt;运行结果为9。我们来分析一下。makePower函数接受参数power，在其内部定义了一个函数powerFn，它接受参数base，并使用到了power的值，makePower函数将powerFn作为它的返回值。那么square也是一个函数，它相当于Math.Pow(base, power)，这里的power值为2.0。问题是power不在powerFn的作用域内，调用makePower结束后，它的就不复存在，那么square到哪里去找power的值呢？如果我们这样创建一个新的函数来求数的立方值：&lt;/p&gt;

&lt;pre&gt;F# Code&lt;br /&gt;let cube = makePower 3.0&lt;/pre&gt;

&lt;p&gt;那么运行时就要存储两个power的拷贝了。不仅这样，每个我们用makePower创建的函数都要使用power的一个拷贝，保存这些值的现象称为闭包。
  &lt;br /&gt;上面的&lt;b&gt;闭包保存了宿主函数的参数值&lt;/b&gt;。另外&lt;b&gt;闭包还可以保存宿主函数的局部变量&lt;/b&gt;：&lt;/p&gt;

&lt;pre&gt;F# Code - 闭包（针对宿主函数的局部值）&lt;br /&gt;let makeIncrementer() =&lt;br /&gt;    let n = ref 0&lt;br /&gt;    &lt;br /&gt;    let increment() = &lt;br /&gt;        n := !n + 1&lt;br /&gt;        !n&lt;br /&gt;        &lt;br /&gt;    increment&lt;br /&gt;    &lt;br /&gt;let inc1 = makeIncrementer()&lt;br /&gt;let inc2 = makeIncrementer()&lt;br /&gt;Console.WriteLine(inc1()) // 1&lt;br /&gt;Console.WriteLine(inc1()) // 2&lt;br /&gt;Console.WriteLine(inc1()) // 3&lt;br /&gt;Console.WriteLine(inc2()) // 1&lt;br /&gt;Console.WriteLine(inc2()) // 2&lt;br /&gt;Console.WriteLine(inc2()) // 3&lt;/pre&gt;

&lt;p&gt;这里闭包为increment保存了n的值，n是ref值，所以是可以修改的。&lt;b&gt;局部变量的生命周期不再由简单的作用域来限定了，我们可以得出结论，它们不再保存在堆栈上&amp;#8212;&amp;#8212;而是必须保存在堆上&lt;/b&gt;。闭包使得包内的函数可以访问作用域之外的值，当闭包应用了一个不在其作用域的值时，它会在其宿主作用域中查找。想一想，上面的makeIncrementer、n还有increment，&lt;b&gt;这个小小的封闭体是不是很像面向对象中的类呢&lt;/b&gt;？

  &lt;br /&gt;&lt;b&gt;没有副作用（Side effect）&lt;/b&gt;

  &lt;br /&gt;如果一个函数或表达式改变了某个状态，我们就说该函数或表达式产生了副作用。比如一个函数可能会修改全局/静态变量、参数，写文件，输出到控制台，或者调用其它产生副作用的函数。在纯粹的函数式编程中，函数没有副作用。

  &lt;br /&gt;如果没有副作用，我们的程序还能干什么？在考虑这个问题前，先来想想，没有副作用后，程序会变成什么样子。此时，唯一影响函数返回值的是参数，这样对于相同的参数，它会返回相同的值，而且它对外部状态毫无影响。既然返回值与外部状态无关，&lt;b&gt;单元测试时只要考虑参数&lt;/b&gt;就好了；在&lt;b&gt;调试时则只需检查调用堆栈里的参数&lt;/b&gt;；如果两个函数没有数据的依赖，就&lt;b&gt;不必考虑它们的调用顺序&lt;/b&gt;；&lt;b&gt;函数可以轻松地并行执行&lt;/b&gt;，这里没有死锁；&lt;b&gt;编译器可以调整或合并表达式的求值&lt;/b&gt;，比如用在惰性求值这里。

  &lt;br /&gt;没有副作用，程序的状态该如何保存呢？把函数提升为一等公民了，它就该多做点事情，我们要把状态保存在参数中。&lt;b&gt;如果要保存某个状态一段时间并时不时地对其进行一些修改，可以写个递归函数&lt;/b&gt;。

  &lt;br /&gt;&lt;b&gt;递归（Recursion） &lt;/b&gt;

  &lt;br /&gt;递归是编程中的一个非常重要的概念，它表示函数通过自身进行定义，亦即在定义处调用自身。在函数式编程中常用于表达命令式编程的循环。下面是求阶乘的函数：&lt;/p&gt;

&lt;pre&gt;F# Code - 递归&lt;br /&gt;let rec factorial x =&lt;br /&gt;    match x with&lt;br /&gt;    | x when x &amp;lt; 0 -&amp;gt; failwith &amp;quot;value must be greater than or equal to 0&amp;quot;  &lt;br /&gt;    | 0 -&amp;gt; 1&lt;br /&gt;    | x -&amp;gt; x * factorial(x - 1)&lt;/pre&gt;

&lt;p&gt;使用rec关键字定义递归函数，这里的match表示模式匹配结构。
  &lt;br /&gt;&lt;b&gt;惰性求值（Lazy evaluation）&lt;/b&gt;

  &lt;br /&gt;惰性求值又称延迟求值（Delayed evaluation），它&lt;b&gt;将运算时间推迟到真正要使用运算结果的时候&lt;/b&gt;。

  &lt;br /&gt;在惰性求值之前，我还遇到过两个懒惰的家伙。一个是Lazy load，这个在ORM中是常见的概念：&lt;/p&gt;

&lt;pre&gt;XML Code - iBATIS.NET Lazyload&lt;br /&gt;&amp;lt;resultMap class=&amp;quot;User&amp;quot; id=&amp;quot;User_Result&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;result column=&amp;quot;UserId&amp;quot; property=&amp;quot;UserId&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;result column=&amp;quot;Password&amp;quot; property=&amp;quot;Password&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;result column=&amp;quot;UserId&amp;quot; property=&amp;quot;RoleList&amp;quot; select=&amp;quot;Role_SelectByUserId&amp;quot; lazyLoad=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/resultMap&amp;gt;&lt;/pre&gt;

&lt;p&gt;这是iBATIS.NET中的一段配置，第三个result节点的lazyLoad特性值为true，这意味着对于User类的RoleList属性来说，只有在用到它的时候才会执行SQL语句进行加载。&lt;/p&gt;

&lt;p&gt;另一个是Lazy initialization，Singleton模式的一种实现方式用到了它：&lt;/p&gt;

&lt;pre&gt;C# Code - Singleton模式&lt;br /&gt;public class Singleton&lt;br /&gt;{&lt;br /&gt;    protected Singleton()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Return an instance of Singleton&lt;br /&gt;    public static Singleton Instance&lt;br /&gt;    {&lt;br /&gt;        get { return SingletonCreator.Instance; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private sealed class SingletonCreator&lt;br /&gt;    {&lt;br /&gt;        // Retrieve a single instance of a Singleton&lt;br /&gt;        private static readonly Singleton _instance = new Singleton();&lt;br /&gt;&lt;br /&gt;        // Return an instance of the class&lt;br /&gt;        public static Singleton Instance&lt;br /&gt;        {&lt;br /&gt;            get { return _instance; }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

&lt;p&gt;在F#中，如果要利用延迟求值的特性，必须要显式地声明哪些表达式的求值需要延迟，这个要使用lazy关键字。如果需要对该表达式求值，则要调用Lazy模块的force函数。&lt;b&gt;在调用force函数的时候，它会计算表达式的值，而所求得的值会被缓存起来，再次对表达式应用force函数时，所得的值其实是缓存中的值&lt;/b&gt;。&lt;/p&gt;

&lt;pre&gt;F# Code - 惰性求值&lt;br /&gt;let sixtyWithSideEffect = lazy(printfn &amp;quot;Hello, sixty!&amp;quot;; 30 + 30)&lt;br /&gt;&lt;br /&gt;print_endline &amp;quot;Force value the first time:&amp;quot;&lt;br /&gt;let actualValue1 = Lazy.force sixtyWithSideEffect&lt;br /&gt;&lt;br /&gt;print_endline &amp;quot;Force value the second time:&amp;quot;&lt;br /&gt;let actualValue2 = Lazy.force sixtyWithSideEffect&lt;/pre&gt;

&lt;p&gt;运行结果为：&lt;/p&gt;

&lt;pre&gt;&lt;img align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" height="16" alt="" /&gt;&lt;img align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" height="16" alt="" /&gt;Output&lt;br /&gt;Force value the first time:&lt;br /&gt;Hello, sixty!&lt;br /&gt;Force value the second time:&lt;/pre&gt;

&lt;p&gt;惰性求值可以减少不必要的运算，从而带来&lt;b&gt;性能上的提升&lt;/b&gt;；也可用于构造&lt;b&gt;无穷的数据结构&lt;/b&gt;（如自然数序列）。

  &lt;br /&gt;此外，我在下午1到4点还会听HitFM的Lazy afternoon :-)

  &lt;br /&gt;&lt;b&gt;模式匹配（Pattern matching） &lt;/b&gt;

  &lt;br /&gt;模式匹配不是什么新的创新的特性。事实上，它和函数式编程的关系不大。把产生模式匹配归因于函数式编程的唯一的原因是函数式语言一度提供了模式匹配，然而现在的命令式语言还做不到。&lt;b&gt;模式匹配是指对于一个数据结构，检查其是否包含匹配给定模式的元素&lt;/b&gt;。正则表达式就是一种典型的模式匹配应用，它用于检查字符序列。

  &lt;br /&gt;在F#中，模式匹配允许你根据标识符值的不同进行不同的运算。有点像一连串的if...else结构，也像C#中的switch，但是它更为强大和灵活。看下面Lucas序列的例子，Lucas序列定义跟Fibonacci序列一样，只不过起始值不同：&lt;/p&gt;

&lt;pre&gt;F# Code - Lucas数&lt;br /&gt;let rec luc x =&lt;br /&gt;    match x with&lt;br /&gt;    | x when x &amp;lt;= 0 -&amp;gt; failwith &amp;quot;value must be greater than zero&amp;quot;&lt;br /&gt;    | 1 -&amp;gt; 1&lt;br /&gt;    | 2 -&amp;gt; 3&lt;br /&gt;    | x -&amp;gt; luc(x - 1) + luc(x - 2)&lt;/pre&gt;

&lt;p&gt;这里匹配的对象是x，它是一个整数，除了对基元类型匹配外，还可以对复杂类型进行匹配，下面的例子是对元组进行匹配：&lt;/p&gt;

&lt;pre&gt;F# Code - 对元组应用模式匹配&lt;br /&gt;let myOr b1 b2 =&lt;br /&gt;    match b1, b2 with&lt;br /&gt;    | true, _ -&amp;gt; true&lt;br /&gt;    | _, true -&amp;gt; true&lt;br /&gt;    | _ -&amp;gt; false&lt;/pre&gt;

&lt;p&gt;而模式匹配的常见用法是对列表进行匹配：&lt;/p&gt;

&lt;pre&gt;F# Code - 对列表应用模式匹配&lt;br /&gt;let rec concatenateList list =&lt;br /&gt;    match list with&lt;br /&gt;    | head :: tail -&amp;gt; head @ (concatenateList tail)&lt;br /&gt;    | [] -&amp;gt; []&lt;/pre&gt;

&lt;p&gt;这里的concatenateList函数可将列表的列表拼接为一个列表。
  &lt;br /&gt;考虑到F#跟.NET平台的亲密关系，我们还可以对.NET类型进行匹配。&lt;/p&gt;

&lt;pre&gt;F# Code - 对.NET类型应用模式匹配&lt;br /&gt;let recognizeType (item : obj) =&lt;br /&gt;    match item with&lt;br /&gt;    | :? System.Int32 -&amp;gt; print_endline &amp;quot;An integer&amp;quot;&lt;br /&gt;    | :? System.Double -&amp;gt; print_endline &amp;quot;A double&amp;quot;&lt;br /&gt;    | :? System.String -&amp;gt; print_endline &amp;quot;A string&amp;quot;&lt;br /&gt;    | _ -&amp;gt; print_endline &amp;quot;Unkown type&amp;quot;&lt;/pre&gt;

&lt;p&gt;看到模式匹配有多么灵活和强大了吧？
  &lt;br /&gt;&lt;b&gt;FP对代码结构的影响&lt;/b&gt;

  &lt;br /&gt;这里将从程序架构、类/接口/函数的组织、函数（或方法）的实现这三个层次来讨论。

  &lt;br /&gt;在&lt;b&gt;程序架构&lt;/b&gt;上，FP对代码结构的影响最小，因为此时问题域本身是最重要的，我们得更多地关注层次较高的内容，比如性能、可靠性等。

  &lt;br /&gt;在&lt;b&gt;类/接口/函数的组织&lt;/b&gt;这个层次上，OO的设计仍然不错，它可以较好地分解问题域并构建解决方案。但是在这个层次上OO有些情况下也不是那么奏效了，比如Command模式。Command模式往往表现为仅包含单一方法（比如Do或Execute）的类/接口，这只是穿上了&amp;#8220;类&amp;#8221;的外衣的函数。Visitor模式亦是如此。可以说在FP中，有些模式已经内置在语言中了！

  &lt;br /&gt;在&lt;b&gt;函数（或方法）的实现&lt;/b&gt;这个层次上，FP的影响最大。此时没有&amp;#8220;变量&amp;#8221;了；不再需要类型注解了；控制结构表现为表达式和递归；可以定义局部/嵌套的函数&amp;#8230;&amp;#8230;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;列表（List）是函数式编程（FP）的基础&lt;/strong&gt;。事实上，FP的重要代表Lisp的名字即源自&amp;#8220;List Processing&amp;#8221;，它的发明者&lt;a href="http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)"&gt;John McCarthy&lt;/a&gt;于1960年发表的论文向我们展示了，在只给定几个简单的操作符和一个表示函数的记号的基础上，如何构造出一个完整的编程语言，他的主要思想之一是用一种简单的数据结构列表来表示代码和数据。

  &lt;br /&gt;&lt;strong&gt;链表（Linked list）是Lisp的主要数据结构之一，并且Lisp的源代码本身也由列表构成&lt;/strong&gt;。F#中的列表类型表示为链表，它与C#中的数组、泛型List&amp;lt;T&amp;gt;类型有着明显的不同。链表可以用下面的图表示：&lt;/p&gt;

&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_42.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_20.png" width="248" height="52" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;首先我们来看一下FP中列表的基本操作（其中的代码都由F#实现）。
  &lt;br /&gt;&lt;strong&gt;列表的基本操作&lt;/strong&gt;

  &lt;br /&gt;&lt;strong&gt;cons&lt;/strong&gt;：它是&amp;#8220;construct&amp;#8221;的缩写，用于构造列表，意即将一个元素添加到列表的开头。我们先约定空表表示为[]，在此基础上再约定操作符&amp;#8220;::&amp;#8221;表示cons操作，这样我们就可以构造任意的列表了。如：&lt;/p&gt;

&lt;pre&gt;F# Code - 列表的cons操作&lt;br /&gt;let emptyList = [] // []&lt;br /&gt;let oneItem = 3 :: [] // [3]&lt;br /&gt;let twoItems = 2 :: oneItem // [2; 3]&lt;br /&gt;let threeItems = 1 :: twoItems // [1; 2; 3]&lt;/pre&gt;

&lt;p&gt;可以看到这里是如何通过&amp;#8220;cons&amp;#8221;操作来一步一步构造列表的。
  &lt;br /&gt;&lt;strong&gt;car&lt;/strong&gt;：它表示&amp;#8220;Contents of the Address part of the Register&amp;#8221;，意即列表的第一个元素。F#中使用List模块的hd（Head）函数来执行car操作：&lt;/p&gt;

&lt;pre&gt;F# Code - 列表的car操作&lt;br /&gt;let stringList = [&amp;quot;No &amp;quot;; &amp;quot;one &amp;quot;; &amp;quot;really &amp;quot;; &amp;quot;listens to &amp;quot;; &amp;quot;anyone else.&amp;quot;]&lt;br /&gt;List.hd stringList // &amp;quot;No &amp;quot;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;cdr&lt;/strong&gt;：它表示&amp;#8220;Contents of the Decrement part of the Register&amp;#8221;，意即列表中第一个元素之外的元素。F#中使用List模块的tl（Tail）函数来执行cdr操作：&lt;/p&gt;

&lt;pre&gt;F# Code - 列表的cdr操作&lt;br /&gt;let stringList = [&amp;quot;No &amp;quot;; &amp;quot;one &amp;quot;; &amp;quot;really &amp;quot;; &amp;quot;listens to &amp;quot;; &amp;quot;anyone else.&amp;quot;]&lt;br /&gt;List.tl stringList // [&amp;quot;one &amp;quot;; &amp;quot;really &amp;quot;; &amp;quot;listens to &amp;quot;; &amp;quot;anyone else.&amp;quot;]&lt;/pre&gt;

&lt;p&gt;有了这三种基本操作，其它的操作都可以推导出来了。比如：
  &lt;br /&gt;&lt;strong&gt;concat&lt;/strong&gt;：该操作用于连接两个列表。在F#用&amp;#8220;@&amp;#8221;操作符执行该操作。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let list1 = [2; 3; 4]&lt;br /&gt;let list2 = [5; 6; 7]&lt;br /&gt;let largeList = list1 @ list2&lt;br /&gt;print_any largeList // [2; 3; 4; 5; 6; 7]&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;length&lt;/strong&gt;：该检查列表的元素数量，在F#中使用List模块的length函数：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let list1 = [2; 3; 4]&lt;br /&gt;List.length list1  // 3&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;nth&lt;/strong&gt;：该操作返回列表的第n个元素，在F#中使用List模块的nth函数：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let list1 = [2; 3; 4]&lt;br /&gt;List.nth list1 2  // 4&lt;/pre&gt;

&lt;p&gt;这里代码用来获取list1中的索引（&lt;strong&gt;基于0&lt;/strong&gt;）为2的元素，返回4。

  &lt;br /&gt;现在再来看看List模块还有哪些重要的函数：

  &lt;br /&gt;&lt;strong&gt;List模块（Microsoft.FSharp.Collections.List）的函数&lt;/strong&gt;

  &lt;br /&gt;&lt;strong&gt;List.rev&lt;/strong&gt;：很明显，它可以翻转一个列表。要注意的是该函数会创建整个列表的一个副本，所以要注意性能问题。

  &lt;br /&gt;&lt;strong&gt;List.zip&lt;/strong&gt;：该函数的签名为a&amp;#8217; list -&amp;gt; b&amp;#8217; list -&amp;gt; (a&amp;#8217; * b&amp;#8217;) list，将两个列表打包为一个元组的列表：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;print_any(List.zip [1; 2] [&amp;quot;one&amp;quot;; &amp;quot;two&amp;quot;]) // [(1, &amp;quot;one&amp;quot;); (2, &amp;quot;two&amp;quot;)]&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;List.exists&lt;/strong&gt;：该函数的签名类型为(a&amp;#8217; -&amp;gt; bool) -&amp;gt; a&amp;#8217; list -&amp;gt; &amp;#8216;a，顾名思义，它用于检查列表是否包含了满足指定谓词函数的元素。

  &lt;br /&gt;&lt;strong&gt;List.find&lt;/strong&gt;：该函数的签名类型为(a&amp;#8217; -&amp;gt; bool) -&amp;gt; a&amp;#8217; list -&amp;gt; &amp;#8216;a，可以看到它接受两个参数，第一个参数是谓词函数，第二个参数及传入的列表。可以这么理解，find函数对列表的元素逐一检查，看是否满足上面所说的谓词函数，如果找到了，返回该元素的值，否则抛出异常。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let result =  List.find (fun i -&amp;gt; i * i = 64) [1..10]&lt;br /&gt;print_int result // 8&lt;/pre&gt;

&lt;p&gt;这里检查[1..10]中的每个数字，返回8。但如果找不到任何元素满足的话，会抛出KeyNotFoundException，这时可以使用tryfind，这个类似于C#中TryParse方法。
  &lt;br /&gt;&lt;strong&gt;List.filter&lt;/strong&gt;：该函数接受的参数与find函数类似，不过它的功能是对列表的元素进行过滤，将所有满足谓词函数的元素构造为一个列表返回：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let list3 = List.filter (fun i -&amp;gt; i % 2 = 0) [1..20]&lt;br /&gt;print_any list3 // [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]&lt;/pre&gt;

&lt;p&gt;另外，还有功能强大的&lt;strong&gt;聚合函数（Aggregate Operators）&lt;/strong&gt;，即iter、map和fold。（事实上，F#中的Set、Seq、Option和Array模块都支持这三种操作）

  &lt;br /&gt;&lt;strong&gt;List.iter&lt;/strong&gt;：该函数将枚举列表中的每个元素，并将每个元素应用于指定的函数，如：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;List.iter (fun i -&amp;gt; printfn &amp;quot;List contains %d&amp;quot; i) [1..5]&lt;/pre&gt;

&lt;p&gt;输出结果为：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;List contains 1&lt;br /&gt;List contains 2&lt;br /&gt;List contains 3&lt;br /&gt;List contains 4&lt;br /&gt;List contains 5&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;List.map&lt;/strong&gt;：map函数用将列表转换为另一个列表。它的签名类型为：&lt;/p&gt;

&lt;pre&gt;Type Infomation&lt;br /&gt;(&amp;#8216;a &amp;#8211;&amp;gt; &amp;#8216;b) &amp;#8211;&amp;gt; &amp;#8216;a list &amp;#8211;&amp;gt; &amp;#8216;b list&lt;/pre&gt;

&lt;p&gt;看看这个效果图就容易理解了，对第一个列表的元素逐一应用函数，从而得到一个新的列表：
  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_40.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_19.png" width="358" height="276" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let x = List.map (fun i -&amp;gt; i * (-1)) [1..5]&lt;br /&gt;printfn &amp;quot;%A&amp;quot; x // [-1; -2; -3; -4; -5]&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;List.fold&lt;/strong&gt;：在这三个函数中，fold最为强大，不过也最为复杂。它的功能可以理解为：假定我们有三个值，初始值baseValue，函数fun，列表list，逐一访问list中的每个元素，对其应用函数fun，将fun的执行结果累加到baseValue，fold将baseValue的最终值返回。在逐一访问列表时，可以采用从左到右或从右向左的方式，所以fold函数有两个实现：fold_left和fold_right。&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let accumulate acc x = acc + x&lt;br /&gt;let totalList = List.fold_left accumulate 0 [1..100]&lt;br /&gt;printfn &amp;quot;1+2+..+100 = %d&amp;quot; totalList // 5050&lt;/pre&gt;

&lt;p&gt;这里baseValue是0，函数是accumulate，列表是[1..100]，最终结果为5050。
  &lt;br /&gt;&lt;strong&gt;列表与模式匹配和递归的结合&lt;/strong&gt;

  &lt;br /&gt;初学列表时，容易像C#中的集合类型那样去看待它。最近学习了一下&lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)"&gt;Haskell&lt;/a&gt;，为它的纯粹和优雅所折服，其中的列表部分大量使用了模式匹配和递归，这个过程也让我重新理解了列表。相比于F#的List模块，&lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)"&gt;Haskell&lt;/a&gt;提供了额外的列表操作函数，这里我想通过在F#中实现这些函数来看看如何结合使用列表与模式匹配和递归。

  &lt;br /&gt;&lt;strong&gt;take&lt;/strong&gt;：接受两个参数，一个数字，一个列表，用于从列表开头获取指定个数的元素组成的新列表：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let rec take (count: int) (l: &amp;#39;a list) =&lt;br /&gt;    match l with&lt;br /&gt;    | _ when count &amp;lt;= 0 -&amp;gt; []&lt;br /&gt;    | [] -&amp;gt; []&lt;br /&gt;    | x :: xs -&amp;gt; x :: take (count - 1) xs&lt;br /&gt;&lt;br /&gt;let list1 = [1; 2; 3; 4; 5]&lt;br /&gt;print_any(take 0 list1) // []&lt;br /&gt;print_any(take 1 list1) // [1]&lt;br /&gt;print_any(take 3 list1) // [1; 2; 3]&lt;/pre&gt;

&lt;p&gt;这里同时使用了递归和模式匹配，如果count小于等于0，返回空列表；否则返回从开头计数的指定个数的元素。
  &lt;br /&gt;&lt;strong&gt;drop&lt;/strong&gt;：该函数也接受两个参数，从列表开头移除指定个数的元素，将剩下的元素组成的列表返回：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;let rec drop (count: int) (l: &amp;#39;a list) =&lt;br /&gt;    match l with&lt;br /&gt;    | _ when count &amp;lt;= 0 -&amp;gt; l&lt;br /&gt;    | [] -&amp;gt; []&lt;br /&gt;    | &lt;strong&gt;head :: tail&lt;/strong&gt; -&amp;gt; drop (count - 1) tail&lt;br /&gt;    &lt;br /&gt;let list1 = [1; 2; 3; 4; 5]&lt;br /&gt;print_any(drop 0 list1) // [1; 2; 3; 4; 5]&lt;br /&gt;print_any(drop 1 list1) // [2; 3; 4; 5]&lt;br /&gt;print_any(drop 5 list1) // []&lt;/pre&gt;

&lt;p&gt;如果count小于等于0，返回原列表；否则移除指定个数的元素。这里使用了&lt;strong&gt;head&lt;/strong&gt;和&lt;strong&gt;tail&lt;/strong&gt;，这样代码的可读性会更好。

  &lt;br /&gt;通过take和drop函数，我们可以看到，&lt;strong&gt;首先得把列表理解为链表，然后在此基础上应用递归和模式匹配，就可以完成很多复杂的操作&lt;/strong&gt;。

  &lt;br /&gt;&lt;strong&gt;小结&lt;/strong&gt;

  &lt;br /&gt;本文介绍了函数式编程（FP）中的列表操作。首先是函数式编程中列表的三种基本操作，在此基础上我们可以推导出其它的各种操作；随后介绍了F#中List模块中的重要函数；最后通过两个自定义函数来展示如何结合使用列表、递归和模式匹配。顺便提一句，强烈建议你学习一下Haskell来了解FP的基本思想，在F#中很容易就能使用命令式编程的方式编写程序，这种灵活性往往使人偏离FP，尤其是在初学FP时。这就像我们学习英语的过程，想象一下，如果把你空投到美国（或其它英语国家），你的英语的进步是不是会快得多？&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;F#代码的组织&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;前言&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;是的，我们已经学习了如何在F#中使用各种范式（函数式、命令式、面向对象）进行编程。但是目前还仅限于在单个模块内编写，要知道，不管是采用哪种语言或者范式编程，如果项目规模大了，都不适合把所有代码放在单个模块内。
  &lt;br /&gt;在常规的.NET项目中（比如C#+ASP.NET），我们往往会选择使用Solution的概念作为整个（独立）问题域的解决方案，Solution以下则是Project、File。这些概念在物理上往往表现为程序集（类库或可执行程序）、类文件等，如果项目和文件数量较多，就该好好考虑如何在组织它们。下面从这三个层次上分别来讨论一下。

  &lt;br /&gt;&lt;strong&gt;Solution层次&lt;/strong&gt;

  &lt;br /&gt;这里主要考虑的是Project之间的相互关系，此时基本上我们可以忽略语言的不同，也&lt;strong&gt;可以说在这个层次上，语言的影响不大&lt;/strong&gt;。所以说我们把那些在用C#开发时采用的代码组织原则搬过来用。比如Martin Fowler在《企业应用架构模式》中谈到的内容，比如Robert Martin在《敏捷软件开发》中提到的关于包的设计原则，还包括.NET社区中关于PetShop架构的讨论等等，都可以加以借鉴。关于这方面的内容已有大量相关的讨论，在此不再赘述。

  &lt;br /&gt;这里只谈一个具体的问题：&lt;strong&gt;如何添加对其它程序集的引用&lt;/strong&gt;。在F# CTP 1.9.6.0之前，添加对程序集的引用需要#I和#r指令，#I用来指定要引用的程序集的目录，#r则用来指定要引用程序集的路径（包含文件名，可以是相对路径或绝对路径）。这两个指令既可以放在代码文件中，也可以放在编译选项中。其中有个小窍门，注册表中.NETFramework节点下包含了各.NET版本的一些信息，其中的&lt;strong&gt;AssemblyFoldersEx&lt;/strong&gt;中有若干个目录信息，如果程序集所在目录出现在AssemblyFoldersEx中，就可以直接使用#r和文件名来添加引用了。

  &lt;br /&gt;在CTP版本中，可以像常规的C#/VB.NET项目中那样，为项目添加对其它程序集的引用（包括引用同一解决方案中的其它项目）：

  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_44.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_21.png" width="283" height="182" /&gt;&lt;/a&gt; 

  &lt;br /&gt;而#r只能用于fsx脚本文件或者放在编译选项中。

  &lt;br /&gt;&lt;strong&gt;Project层次&lt;/strong&gt;

  &lt;br /&gt;现在假定你已经对上述设计原则有了足够的了解，并运用这些原则完成了设计，下一步就是如何使用F#来实现这些设计。现在我们进入到了Project这个层次，需要考虑Project中各代码实体之间的关系，这些实体可以是物理上的源码文件，也可以是逻辑上的模块、类型、配置等。F#中最基本的组织结构是命名空间和模块，命名空间的概念与C#中的一样。借助于Reflector可以看到模块在编译之后就是静态类，我们在为模块添加成员时要了解，这是在向一个静态类添加成员。。

  &lt;br /&gt;&lt;strong&gt;File层次&lt;/strong&gt;

  &lt;br /&gt;现在考虑源码文件内部的基本问题。在&lt;strong&gt;使用函数式编程范式&lt;/strong&gt;时，除了模块，还可以采用&lt;strong&gt;F#的自定义类型&lt;/strong&gt;，F#中的类型分为两类，一是元组（Tuple）或记录（Record）类型，它们类似于C#中的类；二是Union类型，有时又称为Sum类型。通过Reflector可以看到，元组值是Tuple类型的实例，而Tuple实现了 Microsoft.FSharp.Core.IStructuralHash和System.IComparable接口；记录和Union则直接实现了这两个接口。要了解IStructualHash接口的更多内容，请参考&lt;a href="http://blogs.msdn.com/jomo_fisher/archive/2007/09/17/adventures-in-f-discriminated-unions.aspx"&gt;Jome Fisher&lt;/a&gt;的文章。

  &lt;br /&gt;而在使用&lt;strong&gt;面向对象编程范式&lt;/strong&gt;时，我们可以像在C#中那样定义.NET类型，比如接口、类、结构、枚举、委托等等。当然这其中的编程细节比较多，而且对于同一问题可以采取不同的方案。这需要我们去多多学习和实战，根据不同的需要作出选择。

  &lt;br /&gt;这里来看另一个具体的问题：如何使用F#中的&lt;strong&gt;签名文件&lt;/strong&gt;（Signature file）。在学习C语言时，接触过&lt;strong&gt;函数原型&lt;/strong&gt;的概念，它给出了函数的名称、参数类型和返回类型，函数签名的含义与函数原型是一样的。如果我们把模块内的函数签名抽取出来，放在单独的一个文件中，这就是签名文件的由来。它的作用在于，它可以控制模块内函数的访问修饰符。如果要使用签名文件，那么它必须与其控制的模块文件成对出现，并且文件名相同。比如：&lt;/p&gt;

&lt;pre&gt;F# Code - myModule.fsi&lt;br /&gt;#light&lt;br /&gt;module FsLib.MyModule&lt;br /&gt;&lt;br /&gt;/// 获取一个浮点数的平方值&lt;br /&gt;val square: float -&amp;gt; float&lt;br /&gt;&lt;br /&gt;/// 获取一个浮点数的立方值&lt;br /&gt;val cube: float -&amp;gt; float&lt;/pre&gt;

&lt;pre&gt;F# Code - myModule.fs&lt;br /&gt;#light&lt;br /&gt;module FsLib.MyModule&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;&lt;br /&gt;let pow x y = Math.Pow(x, y)&lt;br /&gt;&lt;br /&gt;let square x = pow x 2.0&lt;br /&gt;let cube x = pow x 3.0&lt;/pre&gt;

&lt;p&gt;*.fsi即签名文件，这里定义了两个函数的签名：square和cube。*.fs即实现文件，它必须要提供对应的签名文件的所有函数的实现。其它程序集的模块，只能访问*.fsi中具有签名的函数。通过Reflector可以看到，对于myModule.fs中的三个函数，square和cube的修饰符为&lt;strong&gt;public&lt;/strong&gt;，而pow则为&lt;strong&gt;internal&lt;/strong&gt;。

  &lt;br /&gt;由此看来&lt;strong&gt;签名文件的作用很像C#中的接口&lt;/strong&gt;。但事实上，编译后并没有真正生成接口。需要注意的是，如果要为代码添加XML文档注释，需要加在签名文件（如果模块有的话）而不是模块中。下面来看看如何在代码中添加注释。

  &lt;br /&gt;&lt;strong&gt;常规注释&lt;/strong&gt;

  &lt;br /&gt;在F#中，单行注释使用//，而多行注释则使用(* &amp;#8230; *)。

  &lt;br /&gt;&lt;strong&gt;XML文档注释 &lt;/strong&gt;

  &lt;br /&gt;如果为代码添加了文档注释，可以在编译时生成XML文档，然后借助于一些工具（如SandCastle）就可以生成容易使用的帮助文档。在上面的代码中可以看到，直接使用///可以为模块或其成员添加文档注释，这个要比C#中简便一些。同时也完全可以使用C#中那样完整的文档注释格式（比如使用Summary、Param等节点）。

  &lt;br /&gt;最后，如果要&lt;strong&gt;在F#使用C#类库中的代码&lt;/strong&gt;，可以参考前面写过的了解关于这方面的内容。

  &lt;br /&gt;F#的Project可以编译为类库或可执行应用程序（控制台应用程序或Windows应用程序）。我打算在后面的随笔就这两方面展开讨论，并尝试一些有实战意义的小型项目，相信到那时对代码组织的认识会更为准确。

  &lt;br /&gt;&lt;strong&gt;小结 &lt;/strong&gt;

  &lt;br /&gt;在初学F#时，我们可以很随便地将代码放在同一模块内做些尝试或者测试。但我们程序员不该是随便的人，随着项目规模的增大，代码的组织问题会变得越发重要，我们应当越加重视。在VS中进行开发时， 整个项目的组织自然地分为了Solution、Project、File三个层次，本文在这三个层次上就代码组织的基本问题做了讨论，写得比较简单，欢迎您来留言讨论 。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;在F#中进行单元测试&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;单元测试&lt;/strong&gt;是开发者编写的一小段代码，用于检验被测代码的一个很小的、很明确的功能是否正确。通常情况下，一个单元测试（用例）用于判断某个特定条件（或场景）下特定函数的行为。如果想对单元测试的好处有更多的了解。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;在F#中， &lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/05/30/language-oriented-programming-in-f.aspx"&gt;LOP&lt;/a&gt;（&lt;a href="http://en.wikipedia.org/wiki/Language-oriented_programming"&gt;Language-Oriented Programming&lt;/a&gt;）是它的一个亮点，而FsUnit则是LOP的一个很好的实践。&lt;a href="http://code.google.com/p/fsunit/"&gt;FsUnit&lt;/a&gt;使用F#开发，用它编写的测试用例会接近于自然语言（英语），在其中我们也可以看到F#对函数进行组合的强大威力。&lt;/p&gt;

&lt;p&gt;在本文中，我将通过简单的例子分别对NUnit和FsUnit的基本用法进行介绍。假定我们在开发一个类库MyFsLib，其中有一个模块mathHelper，里面有一些关于数学的函数，现在要做的就是测试这些函数。mathHelper的代码如下：&lt;/p&gt;

&lt;pre&gt;F# Code - mathHelper的签名&lt;br /&gt;#light&lt;br /&gt;module MyFsLib.MathHelper&lt;br /&gt;&lt;br /&gt;/// 获取一个浮点数的平方值&lt;br /&gt;val square: float -&amp;gt; float&lt;br /&gt;&lt;br /&gt;/// 获取一个浮点数的立方值&lt;br /&gt;val cube: float -&amp;gt; float&lt;br /&gt;&lt;br /&gt;/// 判断一个整数是否为偶数&lt;br /&gt;val isEven: int -&amp;gt; bool&lt;br /&gt;&lt;br /&gt;/// 判断一个整数是否为奇数&lt;br /&gt;val isOdd: int -&amp;gt; bool&lt;br /&gt;&lt;br /&gt;/// 获取不大于指定正整数的质数数组&lt;br /&gt;val generatePrimes: int -&amp;gt; int array&lt;/pre&gt;

&lt;pre&gt;F# Code - mathHelper的实现&lt;br /&gt;#light&lt;br /&gt;module MyFsLib.MathHelper&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;&lt;br /&gt;let pow x y = Math.Pow(x, y)&lt;br /&gt;&lt;br /&gt;let square x = pow x 2.0&lt;br /&gt;let cube x = pow x 3.0&lt;br /&gt;&lt;br /&gt;let isEven x = x % 2 = 0&lt;br /&gt;let isOdd x = x % 2 = 1&lt;br /&gt;&lt;br /&gt;// Eratosthenes筛法&lt;br /&gt;let generatePrimes n =&lt;br /&gt;    match n with&lt;br /&gt;    | _ when n &amp;lt; 2 -&amp;gt; [||]&lt;br /&gt;    | _ -&amp;gt;&lt;br /&gt;        // Init sieve.&lt;br /&gt;        let sieve = [| for i in 0 .. n do yield true |]&lt;br /&gt;       &lt;br /&gt;        let isPrime index = sieve.[index]&lt;br /&gt;       &lt;br /&gt;        // Check it.&lt;br /&gt;        let upperBound = Convert.ToInt32(Math.Sqrt((float)n))&lt;br /&gt;        for i = 2 to upperBound do&lt;br /&gt;            if isPrime i then&lt;br /&gt;                for j in [i * 2 .. i .. sieve.Length - 1] do&lt;br /&gt;                    sieve.[j] &amp;lt;- false&lt;br /&gt;                   &lt;br /&gt;        let mutable count = 0&lt;br /&gt;        for i = 2 to sieve.Length - 1 do&lt;br /&gt;            if isPrime i then&lt;br /&gt;                count &amp;lt;- count + 1&lt;br /&gt;               &lt;br /&gt;        let primes = Array.create count 0&lt;br /&gt;        let mutable index = 0&lt;br /&gt;        for i = 2 to sieve.Length - 1 do&lt;br /&gt;            if isPrime i then&lt;br /&gt;                primes.[index] &amp;lt;- i&lt;br /&gt;                index &amp;lt;- index + 1&lt;br /&gt;               &lt;br /&gt;        primes&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;使用NUnit进行单元测试&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;不要害怕，由于F#植根于.NET平台的本性，你会发现这些测试用例代码都是那么眼熟。&lt;/p&gt;

&lt;p&gt;需要废话的是，先添加对&amp;#8221;nunit.framework.dll&amp;#8221;的引用，而且要为测试类添加一个无参构造函数。&lt;/p&gt;

&lt;pre&gt;F# Code - NUnit tester&lt;br /&gt;#light&lt;br /&gt;namespace NUnitTester&lt;br /&gt;&lt;br /&gt;open NUnit.Framework&lt;br /&gt;open MyFsLib&lt;br /&gt;&lt;br /&gt;[&amp;lt;TestFixture&amp;gt;]&lt;br /&gt;type TestCases = class&lt;br /&gt;    new() = {}&lt;br /&gt;   &lt;br /&gt;    [&amp;lt;Test&amp;gt;]&lt;br /&gt;    member this.TestSquare() =&lt;br /&gt;        Assert.AreEqual(0, MathHelper.square(0.0))&lt;br /&gt;        Assert.AreEqual(4, MathHelper.square(2.0))&lt;br /&gt;       &lt;br /&gt;    [&amp;lt;Test&amp;gt;]&lt;br /&gt;    member this.TestGeneratePrimes() =&lt;br /&gt;        let primesLessThan2 = MathHelper.generatePrimes(1)&lt;br /&gt;        CollectionAssert.IsEmpty(primesLessThan2)&lt;br /&gt;       &lt;br /&gt;        let primesNotGreaterThan2 = MathHelper.generatePrimes(2)&lt;br /&gt;        CollectionAssert.IsNotEmpty(primesNotGreaterThan2)&lt;br /&gt;        CollectionAssert.Contains(primesNotGreaterThan2, 2)&lt;br /&gt;        Assert.AreEqual(1, primesNotGreaterThan2.Length)&lt;br /&gt;       &lt;br /&gt;        let primesNotGreaterThan10 = MathHelper.generatePrimes(10)&lt;br /&gt;        CollectionAssert.IsNotEmpty(primesNotGreaterThan10)&lt;br /&gt;        CollectionAssert.Contains(primesNotGreaterThan10, 7)&lt;br /&gt;        Assert.AreEqual(4, primesNotGreaterThan10.Length)&lt;br /&gt;       &lt;br /&gt;    // Other testcases&lt;img alt="" src="http://images.cnblogs.com/dot.gif" /&gt;&lt;br /&gt;end&lt;/pre&gt;

&lt;p&gt;这里只编写了对函数square和generatePrimes的测试。如果你在C#中用过NUnit，看这样的代码就没有任何问题了。测试结果为：
  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_48.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_23.png" width="471" height="318" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;使用FsUnit进行单元测试&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://code.google.com/p/fsunit/"&gt;FsUnit&lt;/a&gt;是一个Specification测试框架。它的目标是将单元测试和行为（函数）的规格尽量简化，并以函数式的风格代替命令式风格的测试代码。&lt;/p&gt;

&lt;p&gt;Specification可以翻译为规格说明，就是说测试代码实际上是对待测代码的一条条规格说明。比如对函数square，它求一个数的平方，那么一条规格可以是：&amp;#8221;square(2) should equal 4&amp;#8221;。好了，惊喜就要来了：&lt;/p&gt;

&lt;pre&gt;&lt;img alt="" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" width="11" height="16" /&gt;&lt;img alt="" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width="11" height="16" /&gt;F# Code - FsUnit tester&lt;br /&gt;#light&lt;br /&gt;&lt;br /&gt;open FsUnit&lt;br /&gt;open MyFsLib&lt;br /&gt;&lt;br /&gt;let squareSpecs =&lt;br /&gt;    specs &amp;quot;Test square&amp;quot; [&lt;br /&gt;        spec &amp;quot;square(0) should equal 0&amp;quot; &lt;br /&gt;            (MathHelper.square(0.0) |&amp;gt; should equal 0.0) // Pass&lt;br /&gt;        spec &amp;quot;square(2) should equal 2&amp;quot; &lt;br /&gt;            (MathHelper.square(2.0) |&amp;gt; should equal 2.0) // Fail&lt;br /&gt;    ]&lt;br /&gt;    &lt;br /&gt;let generatePrimes1Specs =&lt;br /&gt;    specs &amp;quot;Test generatePrimes&amp;quot; [&lt;br /&gt;        spec &amp;quot;generatePrimes(1).Length should equal 0&amp;quot;&lt;br /&gt;            (MathHelper.generatePrimes(1).Length |&amp;gt; should equal 0)&lt;br /&gt;    ]&lt;br /&gt;    &lt;br /&gt;let generatePrimes2Specs =&lt;br /&gt;    specs &amp;quot;Test generatePrimes&amp;quot; [&lt;br /&gt;        spec &amp;quot;generatePrimes(2).Length should equal 1&amp;quot;&lt;br /&gt;            (MathHelper.generatePrimes(2).Length |&amp;gt; should equal 1)&lt;br /&gt;        spec &amp;quot;generatePrimes(2) should contain 2&amp;quot;&lt;br /&gt;            (MathHelper.generatePrimes(2) |&amp;gt; should contain 2)&lt;br /&gt;    ]&lt;br /&gt;    &lt;br /&gt;let generatePrimes10Specs =&lt;br /&gt;    specs &amp;quot;Test generatePrimes&amp;quot; [&lt;br /&gt;        spec &amp;quot;generatePrimes(10).Length should equal 4&amp;quot;&lt;br /&gt;            (MathHelper.generatePrimes(10).Length |&amp;gt; should equal 4)&lt;br /&gt;        spec &amp;quot;generatePrimes(10) should contain 7&amp;quot;&lt;br /&gt;            (MathHelper.generatePrimes(10) |&amp;gt; should contain 7)&lt;br /&gt;        spec &amp;quot;generatePrimes(10) should not contain 9&amp;quot;&lt;br /&gt;            (MathHelper.generatePrimes(10) |&amp;gt; should not&amp;#39; (contain 9))&lt;br /&gt;    ]&lt;br /&gt;    &lt;br /&gt;printfn &amp;quot;%s&amp;quot; (Results.summary())&lt;/pre&gt;

&lt;p&gt;这里没有Assert，有的是should，这两个词给人的感觉可大不一样，而且通过函数的组合，我们可以写出should equal这样的&amp;#8220;句子&amp;#8221;。这里的测试代码已经比较接近自然语言了。&lt;/p&gt;

&lt;p&gt;一条spec就是一条规格说明，它说明待测的函数具有什么样的规格，我们把这些都放在specs中，测试结束后，使用Results.summary函数来显示测试结果：
  &lt;br /&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_46.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_22.png" width="530" height="329" /&gt;&lt;/a&gt; 

  &lt;br /&gt;如果对FsUnit感兴趣，可以到&lt;a href="http://code.google.com/p/fsunit/"&gt;http://code.google.com/p/fsunit/&lt;/a&gt;这里来看看。感觉目前它还有些欠缺，比如没有像CollectionAssert这样的测试类，接下来看看能不能扩展一下。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;小结&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;本文介绍了在F#中如何使用NUnit和FsUnit进行单元测试。可以看到两者都很简单，前者简单是因为能很好地延续在C#中的方式，迁移过来不要费多大力气；后者简单是因为它接近自然语言，看起来很亲切。FsUnit值得关注，除了单元测试本身，我们还可以通过它来了解Language-Oriented Programming的相关知识。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;理解F#中的模式匹配与活动模式&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;模式匹配&lt;/strong&gt;（Pattern Matching）允许我们根据标识符值的不同进行不同的运算，它通常被拿来跟C#中的if&amp;#8230;else或switch语法结构相比较，结论往往是模式匹配比后者要更为灵活、强大。那先来分析一下它灵活、强大在哪儿。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么说模式匹配是灵活、强大的？&lt;/strong&gt;

  &lt;br /&gt;在我前面写过的几篇随笔里面，有几次提到了模式匹配，比如它能够对&lt;strong&gt;简单值&lt;/strong&gt;（整数、字符串）匹配，也可以对&lt;strong&gt;.NET类型&lt;/strong&gt;进行匹配，看下面两个简单的例子：&lt;/p&gt;

&lt;pre&gt;F# Code - 对简单值和.NET类型进行匹配&lt;br /&gt;// 对简单值进行匹配。&lt;br /&gt;let rec fibonacci x =&lt;br /&gt;    match x with&lt;br /&gt;    | x when x &amp;lt;= 0 -&amp;gt; failwith &amp;quot;x必须是正整数。&amp;quot;&lt;br /&gt;    | 1 -&amp;gt; 1&lt;br /&gt;    | 2 -&amp;gt; 1&lt;br /&gt;    | x -&amp;gt; fibonacci(x - 1) + fibonacci(x - 2)&lt;br /&gt;  &lt;br /&gt;printfn &amp;quot;%i&amp;quot; (fibonacci 2) // -&amp;gt; 1&lt;br /&gt;printfn &amp;quot;%i&amp;quot; (fibonacci 4) // -&amp;gt; 3&lt;br /&gt;&lt;br /&gt;// 对.NET类型进行匹配。&lt;br /&gt;open System&lt;br /&gt;let typeToString x =&lt;br /&gt;    match box x with&lt;br /&gt;    | :? Int32 -&amp;gt; &amp;quot;Int32&amp;quot;&lt;br /&gt;    | :? Double -&amp;gt; &amp;quot;Double&amp;quot;&lt;br /&gt;    | :? String -&amp;gt; &amp;quot;String&amp;quot;&lt;br /&gt;    | _ -&amp;gt; &amp;quot;Other Type&amp;quot;&lt;/pre&gt;

&lt;p&gt;可以看到，这里所用的模式匹配没有给人太多惊喜，不用费多大力气就可以将其转换为if&amp;#8230;else或switch结构了。
  &lt;br /&gt;先别急着离开，列表是FP中的典型数据结构，我们对它应用一下模式匹配看看。&lt;/p&gt;

&lt;pre&gt;F# Code - 对列表应用模式匹配&lt;br /&gt;// 对列表应用模式匹配。&lt;br /&gt;let listOfList = [[2; 3; 5]; [7; 11; 13]; [17; 19; 23; 29]]&lt;br /&gt;&lt;br /&gt;let rec concatenateList list =&lt;br /&gt;    match list with&lt;br /&gt;    | head :: tail -&amp;gt; head @ (concatenateList tail)&lt;br /&gt;    | [] -&amp;gt; []&lt;br /&gt;   &lt;br /&gt;let rec concatenateList2 list =&lt;br /&gt;    if List.nonempty list then&lt;br /&gt;        let head = List.hd list in&lt;br /&gt;        let tail = List.tl list in&lt;br /&gt;        head @ (concatenateList2 tail)&lt;br /&gt;    else&lt;br /&gt;        []&lt;br /&gt;        &lt;br /&gt;let primes = concatenateList listOfList&lt;br /&gt;print_any primes // [2; 3; 5; 7; 11; 13; 17; 19; 23; 29]&lt;/pre&gt;

&lt;p&gt;listOfList是一个列表的列表，两个函数concatenateList和concatenateList2的功能都是将listOfList的元素连接为一个大的列表，只不过一个用模式匹配方式实现，一个使用if&amp;#8230;then&amp;#8230;else结构实现。可以看到concatenateList的代码更为简洁，但仅仅如此吗？在concatenateList2中，我们按照传统的看待链表（F#中的列表以链表实现）的方式，将其中的节点一个一个取出来进行处理，这种处理方式是较为&lt;strong&gt;具体和细节&lt;/strong&gt;的；而在concatenateList中我们通过两个简单的模式&amp;#8220;head :: tail&amp;#8221;和&amp;#8220;[]&amp;#8221;就覆盖了列表的所有可能，可以说，&lt;strong&gt;我们找到了更好地分解列表这种数据结构的方式，从而可以更为通用地处理列表&lt;/strong&gt;。

  &lt;br /&gt;类似的，再来看看Union类型的情况。&lt;strong&gt;Union类型&lt;/strong&gt;，有时称为sum类型或discriminated union，可将一组具有不同含义或结构的数据组合在一起。它的一个典型应用是表示一颗树：&lt;/p&gt;

&lt;pre&gt;F# Code - 对Union类型应用模式匹配&lt;br /&gt;type BinaryTree&amp;lt;&amp;#39;a&amp;gt; =&lt;br /&gt;    | Leaf of &amp;#39;a&lt;br /&gt;    | Node of BinaryTree&amp;lt;&amp;#39;a&amp;gt; * BinaryTree&amp;lt;&amp;#39;a&amp;gt; &lt;br /&gt;    &lt;br /&gt;let rec printBinaryTreeValues t =&lt;br /&gt;    match t with&lt;br /&gt;    | Leaf x -&amp;gt; printfn &amp;quot;%i&amp;quot; x&lt;br /&gt;    | Node (l, r) -&amp;gt;&lt;br /&gt;        printBinaryTreeValues l&lt;br /&gt;        printBinaryTreeValues r&lt;br /&gt;        &lt;br /&gt;printBinaryTreeValues (Node ((Node (Leaf 1, Leaf 2)), (Node (Leaf 3, Leaf 4))))&lt;/pre&gt;

&lt;p&gt;这里通过BinaryTree&amp;lt;&amp;#39;a&amp;gt;定义一个泛型二叉树类型，printBinaryTreeValues函数用于打印其节点的值，这里需要判断节点的类型（子树还是叶子），有趣的是，Leaf和Node自动抽象为&amp;#8220;模式&amp;#8221;，不需要任何额外的工作。这样就可以看到一些所谓&amp;#8220;灵活、强大&amp;#8221;的影子了，&lt;strong&gt;对于Union类型所表示的数据结构，模式匹配可以极为简单、自然地分解、处理它&lt;/strong&gt;。

  &lt;br /&gt;除了列表和Union类型，元组对于模式匹配的&amp;#8220;自适应&amp;#8221;也是类似的，这些已经够我们解决很多问题了。那对于其它的更复杂的场景或者更特殊的领域，F#还有什么大招呢？你一定能想得到，这就是活动模式。

  &lt;br /&gt;&lt;strong&gt;活动模式（Active Pattern）&lt;/strong&gt;

  &lt;br /&gt;&lt;strong&gt;活动模式的思想就是把模式匹配语法用于其他更多的数据结构&lt;/strong&gt;。可以把它分为Single-Case、Multi-Case、Partial这几种类型。我将逐一做出介绍。

  &lt;br /&gt;&lt;strong&gt;Single-Case活动模式&lt;/strong&gt;

  &lt;br /&gt;Single-Case是最简单的活动模式形式，它将一个输入值转换为其它的值，比如：&lt;/p&gt;

&lt;pre&gt;F# Code - Single-Case活动模式&lt;br /&gt;let (|UpperCase|) (x:string) = x.ToUpper()&lt;br /&gt;let result = match &amp;quot;foo&amp;quot; with&lt;br /&gt;             | UpperCase &amp;quot;FOO&amp;quot; -&amp;gt; true&lt;br /&gt;             | _ -&amp;gt; false&lt;br /&gt;             &lt;br /&gt;printfn &amp;quot;%b&amp;quot; result // -&amp;gt; true&lt;/pre&gt;

&lt;p&gt;这里的UpperCase就是一个模式，它的类型信息为：active recognizer UpperCase: string -&amp;gt; string，可以看到下面求result值的时候可以像前面一样使用模式匹配的语法了，UpperCase &amp;#8220;FOO&amp;#8221;可以理解为对于输入值&amp;#8221;foo&amp;#8221;，应用了UpperCase模式后，结果应当为&amp;#8221;FOO&amp;#8221;，如果确实如此，那么该模式就匹配了，所以result的值为true。
  &lt;br /&gt;UpperCase模式看起来像是一个函数，不过对于函数来说，没法直接应用模式匹配的语法。

  &lt;br /&gt;&lt;strong&gt;Multi-Case活动模式&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;F# Code - Multi-Case活动模式&lt;br /&gt;let (|Odd|Even|) x = if x % 2 = 0 then Even else Odd&lt;br /&gt;let isDivisibleByTwo x = match x with Even -&amp;gt; true | Odd -&amp;gt; false&lt;br /&gt;print_any (isDivisibleByTwo 2) // -&amp;gt; true&lt;br /&gt;print_any (isDivisibleByTwo 3) // -&amp;gt; false&lt;/pre&gt;

&lt;p&gt;这里(|Odd|Even|)就是Multi-Case模式了，Even的类型信息为：active recognizer Even: int -&amp;gt; unit，即它没有返回值，所以在匹配时，直接写Even或Odd就可以了。
  &lt;br /&gt;&lt;strong&gt;Partial活动模式&lt;/strong&gt;

  &lt;br /&gt;简单来说，&lt;strong&gt;Partial模式就是那些并不总是返回值的模式&lt;/strong&gt;。比如输入值的范围可能过于庞大，或者对于某些返回值我们并不感兴趣，可以将其忽略。比如，对于自然数来说，只有一小部分是完全平方数或者能够被7整除。&lt;/p&gt;

&lt;pre&gt;F# Code - Partial活动模式&lt;br /&gt;// Partial Active Patterns&lt;br /&gt;open System&lt;br /&gt;let (|DivisibleBySeven|_|) input = if input % 7 = 0 then Some() else None&lt;br /&gt;&lt;br /&gt;let (|IsPerfectSquare|_|) (input : int) =&lt;br /&gt;    let sqrt = int (Math.Sqrt(float input))&lt;br /&gt;    if sqrt * sqrt = input then&lt;br /&gt;        Some()&lt;br /&gt;    else&lt;br /&gt;        None&lt;br /&gt;&lt;br /&gt;let describeNumber x =&lt;br /&gt;    match x with&lt;br /&gt;    | DivisibleBySeven &amp;amp; IsPerfectSquare -&amp;gt; &lt;br /&gt;        printfn &amp;quot;x is divisible by 7 and is a perfect square.&amp;quot;&lt;br /&gt;    | DivisibleBySeven                   -&amp;gt; printfn &amp;quot;x is divisible by seven.&amp;quot;&lt;br /&gt;    | IsPerfectSquare                    -&amp;gt; printfn &amp;quot;x is a perfect square.&amp;quot;&lt;br /&gt;    | _                                  -&amp;gt; printfn &amp;quot;x looks normal.&amp;quot;&lt;br /&gt;    &lt;br /&gt;describeNumber 49 // x is divisible by 7 and is a perfect square.&lt;br /&gt;describeNumber 35 // x is divisible by seven.&lt;br /&gt;describeNumber 25 // x is a perfect square.&lt;br /&gt;describeNumber 20 // x looks normal.&lt;/pre&gt;

&lt;p&gt;自然数有很多特性，而在函数describeNumber中，我们只关注它是否是完全平方数或者7的倍数，其它的就都舍弃不管了。
  &lt;br /&gt;&lt;strong&gt;应用&lt;/strong&gt;

  &lt;br /&gt;我们来看看如何使用活动模式来操作XML文档。&lt;/p&gt;

&lt;pre&gt;F# Code - 应用活动模式操作XML文档&lt;br /&gt;// 定义针对XML节点的模式&lt;br /&gt;let (|Node|Leaf|) (node : #System.Xml.XmlNode) =&lt;br /&gt;     if node.HasChildNodes then&lt;br /&gt;         Node (node.Name, { for x in node.ChildNodes -&amp;gt; x })&lt;br /&gt;     else&lt;br /&gt;         Leaf (node.InnerText)&lt;br /&gt;&lt;br /&gt;// 打印XML节点的函数 &lt;br /&gt;let printXml node =&lt;br /&gt;     let rec printXml indent node =&lt;br /&gt;         match node with&lt;br /&gt;         | Leaf (text) -&amp;gt; printfn &amp;quot;%s%s&amp;quot; indent text&lt;br /&gt;         | Node (name, nodes) -&amp;gt;&lt;br /&gt;             printfn &amp;quot;%s%s:&amp;quot; indent name&lt;br /&gt;             nodes |&amp;gt; Seq.iter (printXml (indent + &amp;quot;    &amp;quot;))&lt;br /&gt;     printXml &amp;quot;&amp;quot; node&lt;br /&gt;     &lt;br /&gt;// 定义XML节点&lt;br /&gt;let doc =&lt;br /&gt;    let temp = new System.Xml.XmlDocument()&lt;br /&gt;    let text =  &amp;quot;&amp;lt;fruit&amp;gt;&lt;br /&gt;                 &amp;lt;apples&amp;gt;&lt;br /&gt;                     &amp;lt;gannySmiths&amp;gt;1&amp;lt;/gannySmiths&amp;gt;&lt;br /&gt;                     &amp;lt;coxsOrangePippin&amp;gt;3&amp;lt;/coxsOrangePippin&amp;gt;&lt;br /&gt;                 &amp;lt;/apples&amp;gt;&lt;br /&gt;                 &amp;lt;organges&amp;gt;2&amp;lt;/organges&amp;gt;&lt;br /&gt;                 &amp;lt;bananas&amp;gt;4&amp;lt;/bananas&amp;gt;&lt;br /&gt;             &amp;lt;/fruit&amp;gt;&amp;quot;&lt;br /&gt;    temp.LoadXml(text)&lt;br /&gt;    temp&lt;br /&gt;&lt;br /&gt;printXml (doc.DocumentElement :&amp;gt; System.Xml.XmlNode)&lt;/pre&gt;

&lt;p&gt;这里首先定义针对XML节点的模式，然后应用该模式来递归打印出一个XML节点及其子节点的信息。
  &lt;br /&gt;可以看到使用活动模式，寥寥数语就可以描述出XML节点的通用数据结构来了，这为接下来对节点的操作提供了良好的基础，而且我们回归了问题本身&amp;#8212;&amp;#8212;XML文档，而不需要关注具体的编程细节。

  &lt;br /&gt;&lt;strong&gt;小结&lt;/strong&gt;

  &lt;br /&gt;这里先是介绍了F#中模式匹配的用法，这个可以理解为使用F#内置的模式，这样我们就可以处理F#中的值和特定的数据结构，比如列表、Union类型和元组等；接下来更进一步，活动模式把模式匹配的语法用到了其他更多的数据结构，这样模式的应用范围得到了很大的扩展。而且通过活动模式，我们可以将问题域转换为一套术语来表达，从而脱离编程细节回归到问题域本身，这也就有了一些LOP（Language-Oriented Programming）的特点，事实上，活动模式正是F#中LOP的实现方式之一。这个我将在后面的随笔做更深入的讨论。&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;浅析Mandelbrot集合及其图形的绘制&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;引言&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在《Foundations of F#》的第七章中，作者在介绍Math命名空间时举的例子是绘制Mandelbrot集合。这个看起来挺奇怪的东东以前还真没见过，网上一查才知道，原来它是如此的优美动人。由于该集合的定义与分形相关，所以先来了解下分形的概念。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;什么是分形（Fractal）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1967年，美国数学家Mandelbrot曾出这样一个著名的问题：英格兰的海岸线到底有多长？这个问题在数学上可以理解为：&lt;strong&gt;用折线段拟合任意不规则的连续曲线是否一定有效&lt;/strong&gt;？这个问题的提出实际上是对以欧氏几何为核心的传统几何的挑战。&lt;/p&gt;

&lt;p&gt;1975年，Mandelbrot在其《自然界中的分形几何》一书中引入了分形（fractal）这一概念。从字面意义上讲， fractal是碎块、碎片的意思，然而这并不能概括Mandelbrot的分形概念，尽管目前还没有一个让各方都满意的分形定义，但在数学上大家都认为分形有以下几个特点：&lt;/p&gt;

&lt;p&gt;1. 具有无限精细的结构；
  &lt;br /&gt;2. 比例自相似性；

  &lt;br /&gt;3. 一般它的分数维大子它的拓扑维数；

  &lt;br /&gt;4. 可以由非常简单的方法定义，并由递归、迭代产生。&lt;/p&gt;

&lt;ol&gt;&lt;/ol&gt;

&lt;p&gt;据说，南非海岸线的维数是1.02，英国西岸的维数是1.25。 &lt;/p&gt;

&lt;p&gt;下面的两幅图有助于我们理解它的概念： &lt;/p&gt;

&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_58.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_28.png" width="182" height="284" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_56.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_27.png" width="353" height="339" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;需要注意的是，分形往往由递归、迭代产生，但是我们在纸上做出的图只能作有限次的递归、迭代。 &lt;/p&gt;

&lt;p&gt;分形几何学已在自然界与物理学中得到了应用。如在显微镜下观察落入溶液中的一粒花粉，会看见它不间断地作无规则运动（&lt;strong&gt;布朗运动&lt;/strong&gt;），这是花粉在大量液体分子的无规则碰撞（每秒钟多达十亿亿次）下表现的平均行为。布朗粒子的轨迹，由各种尺寸的折线连成。只要有足够的分辨率，就可以发现原以为是直线段的部分，其实由大量更小尺度的折线连成。 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;什么是Mandelbrot集合？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mandelbrot集合&lt;/strong&gt;是在&lt;a href="http://zh.wikipedia.org/wiki/%E5%A4%8D%E5%B9%B3%E9%9D%A2"&gt;复平面&lt;/a&gt;上组成&lt;a href="http://zh.wikipedia.org/wiki/%E5%88%86%E5%BD%A2"&gt;分形&lt;/a&gt;的点的集合，它正是以数学家Mandelbrot命名。&lt;/p&gt;

&lt;p&gt;Mandelbrot集合可以用复二次多项式 &lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&amp;#160;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_60.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_29.png" width="126" height="31" /&gt;&lt;/a&gt; 来定义 &lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;其中&lt;em&gt;c&lt;/em&gt;是一个复参数。对于每一个&lt;em&gt;c&lt;/em&gt;，从&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_64.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_31.png" width="53" height="22" /&gt;&lt;/a&gt; 开始对&lt;em&gt;f&lt;/em&gt;&lt;sub&gt;&lt;em&gt;c&lt;/em&gt;&lt;/sub&gt;(&lt;em&gt;z&lt;/em&gt;)进行迭代。 &lt;/p&gt;

&lt;p&gt;&lt;a href="http://zh.wikipedia.org/wiki/%E5%BA%8F%E5%88%97"&gt;序列&lt;/a&gt;&amp;#160;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_62.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_30.png" width="244" height="24" /&gt;&lt;/a&gt; 的元素的模（复数具有模的概念）或者延伸到无穷大，或者只停留在有限半径的圆盘内。Mandelbrot集合就是使以上序列不延伸至无限大的所有&lt;em&gt;c&lt;/em&gt;点的集合。 &lt;/p&gt;

&lt;p&gt;从数学上来讲，Mandelbrot集合是一个&lt;a href="http://zh.wikipedia.org/wiki/%E5%A4%8D%E6%95%B0"&gt;复数&lt;/a&gt;的集合。一个给定的复数&lt;em&gt;c&lt;/em&gt;或者属于Mandelbrot集合&lt;em&gt;M&lt;/em&gt;，或者不属于。比如，取c = 1，那么这个序列就是(0, 1, 2, 5, 26, ...)，显然它的值会趋于无穷大；而如果取c = i，那么序列就是(0, i, -1+i, -i, -1+i, -i,...)，它的值会一直停留在有限半径的圆盘内。 &lt;/p&gt;

&lt;p&gt;事实上，一&lt;strong&gt;个点属于Mandelbrot集合当且仅当它对应的序列（由上面的二项式定义）中的任何元素的模都不大于2&lt;/strong&gt;。这里的2就是上面提到的&amp;#8220;有限半径&amp;#8221;。 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;在计算机上绘制Mandelbrot集合&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;计算机的屏幕上的像素只有有限个，而Mandelbrot集合中的点则有无限个。 &lt;/p&gt;

&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_54.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_26.png" width="371" height="272" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;观察上面复平面的局部，Mandelbrot集合即黑色区域，实部从-2到1，虚部从-1到1，那么将两个点(-2, 1)和(1, -1)作为一个矩形的左上角顶点和右下角顶点，那么这个矩形就包含了整个Mandelbrot集合，该矩形的长为3，宽为2。我们可以将这个矩形与屏幕上的区域进行映射，也就是将屏幕上的一个像素映射为该矩形内的一点，如果该点属于Mandelbrot集合，就将该像素着为黑色，这样逐一对每个像素进行判断和着色，就可以模拟绘制Mandelbrot集合了。该矩形的长宽比为3：2，我们在屏幕上可以取600 * 400的矩形区域。&lt;/p&gt;

&lt;p&gt;完成映射后来考虑如何判断一个点是否属于该集合。其根据就是上面的结论&amp;#8220;一&lt;strong&gt;个点属于Mandelbrot集合当且仅当它对应的序列（由上面的二项式定义）中的任何元素的模都不大于2&amp;#8221;&lt;/strong&gt;，由于序列的的元素有无穷多个，我们只能取有限的迭代次数来模拟了，比如取100或1000次。&lt;/p&gt;

&lt;p&gt;我们用Microsoft.FSharp.Math.Notation.complex类型来表示一个复数，它的Magnitude属性表示复数的模，我们可以通过一定次数（比如100次）的迭代，来看看前100项是不是都满足条件，如果满足就认为这个复数在Mandelbrot集合内。下面是完整的程序。&lt;/p&gt;

&lt;pre&gt;F# Code - 绘制Mandelbrot集合&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;open System.Drawing&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;open Microsoft.FSharp.Math&lt;br /&gt;open Microsoft.FSharp.Math.Notation&lt;br /&gt;&lt;br /&gt;// 迭代次数&lt;br /&gt;let maxIterations = 100&lt;br /&gt;&lt;br /&gt;// 映射比例&lt;br /&gt;let scalingFactor = 1.0 / 200.0&lt;br /&gt;// 将像素映射为复数&lt;br /&gt;let mapPlane(x, y) =&lt;br /&gt;    let fx = ((float x) * scalingFactor) - 2.0&lt;br /&gt;    let fy = ((float y) * scalingFactor) - 1.0&lt;br /&gt;    complex fx fy&lt;br /&gt;&lt;br /&gt;let mutable iteration = 0&lt;br /&gt;let mutable current = complex 0.0 0.0&lt;br /&gt;let mutable temp = complex 0.0 0.0&lt;br /&gt;&lt;br /&gt;let form =&lt;br /&gt;    let image = new Bitmap(600, 400)&lt;br /&gt;    for x = 0 to image.Width - 1 do&lt;br /&gt;        for y = 0 to image.Height - 1 do&lt;br /&gt;            iteration &amp;lt;- 0&lt;br /&gt;            current &amp;lt;- mapPlane(x, y)&lt;br /&gt;            temp &amp;lt;- current&lt;br /&gt;            // 判断当前点是否在Mandelbrot集合内&lt;br /&gt;            while(temp.Magnitude &amp;lt;= 2.0 &amp;amp;&amp;amp; iteration &amp;lt; maxIterations) do&lt;br /&gt;                temp &amp;lt;- temp * temp + current&lt;br /&gt;                iteration &amp;lt;- iteration + 1&lt;br /&gt;            &lt;br /&gt;            // 如果在，像素为黑色    &lt;br /&gt;            if iteration = maxIterations then&lt;br /&gt;                image.SetPixel(x, y, Color.Black)&lt;br /&gt;            else&lt;br /&gt;                image.SetPixel(x, y, Color.White)&lt;br /&gt;               &lt;br /&gt;    let temp = new Form() in&lt;br /&gt;    temp.Paint.Add(fun e -&amp;gt; e.Graphics.DrawImage(image, 0, 0))&lt;br /&gt;    temp.Height &amp;lt;- 435&lt;br /&gt;    temp.Width &amp;lt;- 600&lt;br /&gt;    temp.Text &amp;lt;- &amp;quot;Draw Mandelbrot Set&amp;quot;&lt;br /&gt;    temp&lt;br /&gt;   &lt;br /&gt;[&amp;lt;STAThread&amp;gt;]&lt;br /&gt;do Application.Run(form)&lt;/pre&gt;

&lt;p&gt;下面是效果图&lt;/p&gt;

&lt;p&gt;&lt;a href="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_52.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px;" border="0" alt="image" src="http://community.icburner.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/webdev/image_5F00_thumb_5F00_25.png" width="562" height="409" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;这张图是黑白的，我们可以把它变成彩色的。看这一部分代码：&lt;/p&gt;

&lt;pre&gt;&lt;br /&gt;// 如果在，像素为黑色    &lt;br /&gt;if iteration = maxIterations then&lt;br /&gt;    image.SetPixel(x, y, Color.Black)&lt;br /&gt;else&lt;br /&gt;    image.SetPixel(x, y, Color.White)&lt;/pre&gt;

&lt;p&gt;只有iteration等于maxIterations，当前的复数才属于Mandelbrot集合，这时将像素着为黑色；如果不在集合内，我们可以想办法着为彩色。考虑红橙黄绿蓝靛紫七种颜色，把它们存储在数组中，然后根据iteration的值来取相应的颜色：&lt;/p&gt;

&lt;pre&gt;Code&lt;br /&gt;// 七种颜色&lt;br /&gt;let colors = [| Color.Red; Color.Orange; Color.Yellow; &lt;br /&gt;                Color.Green; Color.Blue; Color.Indigo; &lt;br /&gt;                Color.Purple; |]&lt;br /&gt;&lt;br /&gt;// 如果在，像素为黑色    &lt;br /&gt;if iteration = maxIterations then&lt;br /&gt;    image.SetPixel(x, y, Color.Black)&lt;br /&gt;else&lt;br /&gt;    image.SetPixel(x, y, colors.[iteration % colors.Length])&lt;/pre&gt;

&lt;p&gt;完整的代码是：&lt;/p&gt;

&lt;pre&gt;F# Code - 彩色的Mandelbrot&lt;br /&gt;#light&lt;br /&gt;open System&lt;br /&gt;open System.Drawing&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;open Microsoft.FSharp.Math&lt;br /&gt;open Microsoft.FSharp.Math.Notation&lt;br /&gt;&lt;br /&gt;// 迭代次数&lt;br /&gt;let maxIterations = 30&lt;br /&gt;&lt;br /&gt;// 七种颜色&lt;br /&gt;let colors = [| Color.Red; Color.Orange; Color.Yellow; &lt;br /&gt;                Color.Green; Color.Blue; Color.Indigo; &lt;br /&gt;                Color.Purple; |]&lt;br /&gt;&lt;br /&gt;// 映射比例&lt;br /&gt;let scalingFactor = 1.0 / 200.0&lt;br /&gt;// 将像素映射为坐标&lt;br /&gt;let mapPlane(x, y) =&lt;br /&gt;    let fx = ((float x) * scalingFactor) - 2.0&lt;br /&gt;    let fy = ((float y) * scalingFactor) - 1.0&lt;br /&gt;    complex fx fy&lt;br /&gt;&lt;br /&gt;let mutable iteration = 0&lt;br /&gt;let mutable current = complex 0.0 0.0&lt;br /&gt;let mutable temp = complex 0.0 0.0&lt;br /&gt;&lt;br /&gt;let form =&lt;br /&gt;    let image = new Bitmap(600, 400)&lt;br /&gt;    for x = 0 to image.Width - 1 do&lt;br /&gt;        for y = 0 to image.Height - 1 do&lt;br /&gt;            iteration &amp;lt;- 0&lt;br /&gt;            current &amp;lt;- mapPlane(x, y)&lt;br /&gt;            temp &amp;lt;- current&lt;br /&gt;            // 判断当前点是否在Mandelbrot集合内&lt;br /&gt;            while(temp.Magnitude &amp;lt;= 2.0 &amp;amp;&amp;amp; iteration &amp;lt; maxIterations) do&lt;br /&gt;                temp &amp;lt;- temp * temp + current&lt;br /&gt;                iteration &amp;lt;- iteration + 1&lt;br /&gt;            &lt;br /&gt;            // 如果在，像素为黑色    &lt;br /&gt;            if iteration = maxIterations then&lt;br /&gt;                image.SetPixel(x, y, Color.Black)&lt;br /&gt;            else&lt;br /&gt;                image.SetPixel(x, y, colors.[iteration % colors.Length])&lt;br /&gt;               &lt;br /&gt;    let temp = new Form() in&lt;br /&gt;    temp.Paint.Add(fun e -&amp;gt; e.Graphics.DrawImage(image, 0, 0))&lt;br /&gt;    temp.Height &amp;lt;- 435&lt;br /&gt;    temp.Width &amp;lt;- 600&lt;br /&gt;    temp.Text &amp;lt;- &amp;quot;Drawing Mandelbrot Set&amp;quot;&lt;br /&gt;    temp&lt;br /&gt;   &lt;br /&gt;[&amp;lt;STAThread&amp;gt;]&lt;br /&