Listing 4-1. The Initial Content of the Home Controller
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } }}
Listing 4-2. The Contents of the Result View File
@model String@{ Layout = null;}Result @Model
Listing 4-3. Defining a Property
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public class Product { private string name; public string Name { get { return name; } set { name = value; } } }}
Listing 4-4. Consuming a Property
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } public ViewResult AutoProperty() { Product product = new Product(); product.Name = "Kayak"; string productName = product.Name; return View("Result", (object)String.Format("Product name: {0}", productName)); } }}
Listing 4-5. Verbose Property Definitions
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public class Product { private int productId; private string name; private string description; private decimal price; private string category; public int ProductId { get { return productId; } set { productId = value; } } public string Name { get { return name; } set { name = value; } } public string Description { get { return description; } set { description = value; } } public decimal Price { get { return price; } set { price = value; } } public string Category { get { return category; } set { category = value; } } }}
Listing 4-6. Using Automatically Implemented Properties
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public class Product { public int ProductId { get; set; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } public string Category { get; set; } }}
Listing 4-7. Reverting from an Automatic to a Regular Property
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public class Product { private string name; public int ProductId { get; set; } public string Name { get { return ProductId + name; } set { name = value; } } public string Description { get; set; } public decimal Price { get; set; } public string Category { get; set; } }}
Listing 4-8. Constructing and Initializing an Object with Properties
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } public ViewResult AutoProperty() { Product product = new Product(); product.Name = "Kayak"; string productName = product.Name; return View("Result", (object)String.Format("Product name: {0}", productName)); } public ViewResult CreateProduct() { Product product = new Product(); product.ProductId = 100; product.Name = "Kayak"; product.Description = "A boat for one person"; product.Price = 275M; product.Category = "Watersports"; return View("Result", (object)String.Format("Category: {0}", product.Category)); } }}
Listing 4-9. Using the Object Initializer Feature
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } public ViewResult AutoProperty() { Product product = new Product(); product.Name = "Kayak"; string productName = product.Name; return View("Result", (object)String.Format("Product name: {0}", productName)); } public ViewResult CreateProduct() { Product product = new Product { ProductId = 100, Name = "Kayak", Description = "A boat for one person", Price = 275M, Category = "Waterports" }; return View("Result", (object)String.Format("Category: {0}", product.Category)); } }}
Listing 4-10. Initializing Collections and Arrays
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } public ViewResult AutoProperty() { Product product = new Product(); product.Name = "Kayak"; string productName = product.Name; return View("Result", (object)String.Format("Product name: {0}", productName)); } public ViewResult CreateProduct() { Product product = new Product { ProductId = 100, Name = "Kayak", Description = "A boat for one person", Price = 275M, Category = "Waterports" }; return View("Result", (object)String.Format("Category: {0}", product.Category)); } public ViewResult CreateCollection() { string[] stringArray = { "apple", "orange", "plum"}; List intList = new List { 10, 20, 30, 40 }; Dictionarydict = new Dictionary { { "apple", 10 }, { "orange", 20 }, { "plum", 30 } }; return View("Result", (object)stringArray[1]); } }}
Listing 4-11. The ShoppingCart Class
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public class ShoppingCart { public ListProducts { get; set; } }}
Listing 4-12. Defining an Extension Method
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public static class MyExtensionMethods { public static decimal TotalPrices(this ShoppingCart cart) { decimal total = 0; foreach (Product prod in cart.Products) { total += prod.Price; } return total; } }}
Listing 4-13. Applying an Extension Method
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseExtension() { // Create and populate ShoppingCart ShoppingCart cart = new ShoppingCart { Products = new List{ new Product{Name = "Kayak", Price = 275M}, new Product{Name = "Lifejacket", Price = 48.95M}, new Product{Name = "Soccer ball", Price = 19.50M}, new Product{Name = "Corner flag", Price = 34.95M} } }; // Get the total value of the products in the cart decimal cartTotal = cart.TotalPrices(); return View("Result", (object)String.Format("Total: {0:c}", cartTotal)); } }}
Listing 4-14. Implementing an Interface in the ShoppingCart Class
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public class ShoppingCart : IEnumerable{ public List Products { get; set; } public IEnumerator GetEnumerator() { return Products.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }}
Listing 4-15. An Extension Method That Works on an Interface
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public static class MyExtensionMethods { public static decimal TotalPrices(this IEnumerableproductEnum) { decimal total = 0; foreach (Product prod in productEnum) { total += prod.Price; } return total; } }}
Listing 4-16. Applying an Extension Method to Different Implementations of the Same Interface
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseExtensionEnumerable() { IEnumerableproducts = new ShoppingCart { Products = new List { new Product{Name = "Kayak", Price = 275M}, new Product{Name = "Lifejacket", Price = 48.95M}, new Product{Name = "Soccer ball", Price = 19.50M}, new Product{Name = "Corner flag", Price = 34.95M} } }; Product[] productArray = { new Product{Name = "Kayak", Price = 275M}, new Product{Name = "Lifejacket", Price = 48.95M}, new Product{Name = "Soccer ball", Price = 19.50M}, new Product{Name = "Corner flag", Price = 34.95M} }; decimal cartTotal = products.TotalPrices(); decimal arrayTotal = productArray.TotalPrices(); return View("Result", (object)String.Format("Cart Total: {0}, Array Total: {1}", cartTotal, arrayTotal)); } }}
Listing 4-17. A Filtering Extension Method
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public static class MyExtensionMethods { public static decimal TotalPrices(this IEnumerableproductEnum) { decimal total = 0; foreach (Product prod in productEnum) { total += prod.Price; } return total; } public static IEnumerable FilterByCategory( this IEnumerable productEnum, string category) { foreach (Product prod in productEnum) { if (prod.Category == category) { yield return prod; } } } }}
Listing 4-18. Using the Filtering Extension Method
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseFilterExtensionMethod() { IEnumerableproducts = new ShoppingCart { Products = new List { new Product{Name = "Kayak", Category = "Watersports", Price = 275M}, new Product{Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product{Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product{Name = "Corner flag", Category = "Soccer", Price = 34.95M} } }; decimal total = 0; foreach (Product prod in products.FilterByCategory("Soccer")) { total += prod.Price; } return View("Result", (object)String.Format("Total: {0}", total)); } }}
Listing 4-19. Using a Delegate in an Extension Method
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace LanguageFeatures.Models{ public static class MyExtensionMethods { public static decimal TotalPrices(this IEnumerableproductEnum) { decimal total = 0; foreach (Product prod in productEnum) { total += prod.Price; } return total; } public static IEnumerable FilterByCategory( this IEnumerable productEnum, string category) { foreach (Product prod in productEnum) { if (prod.Category == category) { yield return prod; } } } public static IEnumerable Filter( this IEnumerable productEnum, Func selector) { foreach (Product prod in productEnum) { if (selector(prod)) { yield return prod; } } } }}
Listing 4-20. Using the Filtering Extension Method with a Func
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseFilterExtensionMethod() { IEnumerableproducts = new ShoppingCart { Products = new List { new Product{Name = "Kayak", Category = "Watersports", Price = 275M}, new Product{Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product{Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product{Name = "Corner flag", Category = "Soccer", Price = 34.95M} } }; Func categoryFilter = delegate(Product prod) { return prod.Category == "Soccer"; }; decimal total = 0; foreach (Product prod in products.Filter(categoryFilter)) { total += prod.Price; } return View("Result", (object)String.Format("Total: {0}", total)); } }}
Listing 4-21. Using a Lambda Expression to Replace a Delegate Definition
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseFilterExtensionMethod() { IEnumerableproducts = new ShoppingCart { Products = new List { new Product{Name = "Kayak", Category = "Watersports", Price = 275M}, new Product{Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product{Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product{Name = "Corner flag", Category = "Soccer", Price = 34.95M} } }; Func categoryFilter = prod => prod.Category == "Soccer"; decimal total = 0; foreach (Product prod in products.Filter(categoryFilter)) { total += prod.Price; } return View("Result", (object)String.Format("Total: {0}", total)); } }}
Listing 4-22. A Lambda Expression Without a Func
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseFilterExtensionMethod() { IEnumerableproducts = new ShoppingCart { Products = new List { new Product{Name = "Kayak", Category = "Watersports", Price = 275M}, new Product{Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product{Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product{Name = "Corner flag", Category = "Soccer", Price = 34.95M} } }; decimal total = 0; foreach (Product prod in products.Filter(prod => prod.Category == "Soccer")) { total += prod.Price; } return View("Result", (object)String.Format("Total: {0}", total)); } }}
Listing 4-23. Extending the Filtering Expressed by the Lambda Expression
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseFilterExtensionMethod() { IEnumerableproducts = new ShoppingCart { Products = new List { new Product{Name = "Kayak", Category = "Watersports", Price = 275M}, new Product{Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product{Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product{Name = "Corner flag", Category = "Soccer", Price = 34.95M} } }; decimal total = 0; foreach (Product prod in products.Filter( prod => prod.Category == "Soccer" || prod.Price > 20)) { total += prod.Price; } return View("Result", (object)String.Format("Total: {0}", total)); } }}
Listing 4-24. Using Type Inference
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseTypeInference() { var myVariable = new Product { Name = "Kayak", Category = "Watersports", Price = 275M }; string name = myVariable.Name; // Legal int price = myVariable.Price; // Compiler error return View("Result", (object)String.Format("Name: {0}, Price: {1}", name, price)); } }}
Listing 4-25. Creating an Anonymous Type
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult UseTypeInference() { var myAnonType = new { Name = "Kayak", Category = "Watersports", Price = 275M }; string name = myAnonType.Name; decimal price = myAnonType.Price; return View("Result", (object)String.Format("Name: {0}, Price: {1}", name, price)); } }}
Listing 4-26. Creating an Array of Anonymously Typed Objects
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult CreateAnonArray() { var oddsAnonEnds = new[] { new {Name = "MVC", Category = "Pattern"}, new {Name = "Hat", Category = "Clothing"}, new {Name = "Apple", Category = "Fruit"} }; StringBuilder result = new StringBuilder(); foreach (var item in oddsAnonEnds) { result.Append(item.Name).Append(" "); } return View("Result", (object)result.ToString()); } }}
Listing 4-27. Querying Without LINQ
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult FindProducts() { Product[] products = { new Product {Name = "Kayak", Category = "Watersports", Price = 275M}, new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M} }; Product[] foundProducts = new Product[3]; Array.Sort(products, (item1, item2) => { return Comparer.Default.Compare(item1.Price, item2.Price); }); Array.Copy(products, foundProducts, 3); StringBuilder result = new StringBuilder(); foreach (Product p in foundProducts) { result.AppendFormat("Price: {0} ", p.Price); } return View("Result", (object)result.ToString()); } }}
Listing 4-28. Using LINQ to Query Data
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult FindProducts() { Product[] products = { new Product {Name = "Kayak", Category = "Watersports", Price = 275M}, new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M} }; var foundProducts = from match in products orderby match.Price descending select new { match.Name, match.Price }; int count = 0; StringBuilder result = new StringBuilder(); foreach (var p in foundProducts) { result.AppendFormat("Price: {0} ", p.Price); if (++count == 3) { break; } } return View("Result", (object)result.ToString()); } }}
Listing 4-29. Using LINQ Dot Notation
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult FindProducts() { Product[] products = { new Product {Name = "Kayak", Category = "Watersports", Price = 275M}, new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M} }; var foundProducts = products.OrderByDescending(e => e.Price) .Take(3) .Select(e => new { e.Name, e.Price }); int count = 0; StringBuilder result = new StringBuilder(); foreach (var p in foundProducts) { result.AppendFormat("Price: {0} ", p.Price); if (++count == 3) { break; } } return View("Result", (object)result.ToString()); } }}
Listing 4-30. Using Deferred LINQ Extension Methods in a Query
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult FindProducts() { Product[] products = { new Product {Name = "Kayak", Category = "Watersports", Price = 275M}, new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M} }; var foundProducts = products.OrderByDescending(e => e.Price) .Take(3) .Select(e => new { e.Name, e.Price }); products[2] = new Product { Name = "Stadium", Price = 79600M }; StringBuilder result = new StringBuilder(); foreach (var p in foundProducts) { result.AppendFormat("Price: {0} ", p.Price); } return View("Result", (object)result.ToString()); } }}
Listing 4-31. An Immediately Executed LINQ Query
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web;using System.Web.Mvc;using LanguageFeatures.Models;namespace LanguageFeatures.Controllers{ public class HomeController : Controller { public string Index() { return "Navigate to a URL to show an example"; } // Other action methods omitted for brevity public ViewResult SumProducts() { Product[] products = { new Product {Name = "Kayak", Category = "Watersports", Price = 275M}, new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M}, new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M}, new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M} }; var results = products.Sum(e => e.Price); products[2] = new Product { Name = "Stadium", Price = 79600M }; return View("Result", (object)String.Format("Sum: {0:c}", results)); } }}
Listing 4-32. A Simple Asynchronous Method
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Net.Http;using System.Threading.Tasks;namespace LanguageFeatures.Models{ public class MyAsyncMethods { public static TaskGetPageLength() { HttpClient client = new HttpClient(); var httpTask = client.GetAsync("http://apress.com"); // We could do other things here while we are waiting // for the HTTP request to complete return httpTask.ContinueWith((Task antecedent) => { return antecedent.Result.Content.Headers.ContentLength; }); } }}
Listing 4-33. Using the async and await Keywords
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Net.Http;using System.Threading.Tasks;namespace LanguageFeatures.Models{ public class MyAsyncMethods { public async static TaskGetPageLength() { HttpClient client = new HttpClient(); var httpMessage = await client.GetAsync("http://apress.com"); // We could do other things here while we are waiting // for the HTTP request to complete return httpMessage.Content.Headers.ContentLength; } }}