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; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Result</title> </head> <body> <div> @Model </div> </body> </html>
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<int> intList = new List<int> { 10, 20, 30, 40 }; Dictionary<string, int> dict = new Dictionary<string, int> { { "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 List<Product> Products { 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<Product> { 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<Product> { public List<Product> Products { get; set; } public IEnumerator<Product> 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 IEnumerable<Product> productEnum) { 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() { IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { 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 IEnumerable<Product> productEnum) { decimal total = 0; foreach (Product prod in productEnum) { total += prod.Price; } return total; } public static IEnumerable<Product> FilterByCategory( this IEnumerable<Product> 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() { IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { 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 IEnumerable<Product> productEnum) { decimal total = 0; foreach (Product prod in productEnum) { total += prod.Price; } return total; } public static IEnumerable<Product> FilterByCategory( this IEnumerable<Product> productEnum, string category) { foreach (Product prod in productEnum) { if (prod.Category == category) { yield return prod; } } } public static IEnumerable<Product> Filter( this IEnumerable<Product> productEnum, Func<Product, bool> 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() { IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { 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<Product, bool> 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() { IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { 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<Product, bool> 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() { IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { 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() { IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> { 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<decimal>.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 Task<long?> GetPageLength() { 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<HttpResponseMessage> 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 Task<long?> GetPageLength() { 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; } } }