.net mvc笔记2_Essential C# Features

时间:2023-03-06 21:52:14

Essential C# Features

1、Using Automatically Implemented Properties

 public class Product {
private string name; public int ProductID { get; set; }
public string Name { //属性Name用常规方式实现
get { return ProductID + name;}
set { name = value; }
} public string Description { get; set;}
public decimal Price { get; set; }
public string Category { set; get;}
}

2、Using Object and Collection Initializers

 Listing -. Constructing and Initializing an Object with Properties旧有做法对比
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
// create a new Product object
Product myProduct = new Product();
// set the property values
myProduct.ProductID = ;
myProduct.Name = "Kayak";
myProduct.Description = "A boat for one person";
myProduct.Price = 275M;
myProduct.Category = "Watersports";
// process the product
ProcessProduct(myProduct);
}
private static void ProcessProduct(Product prodParam)
{
//...statements to process product in some way
}
}
 Listing -. Using the Object Initializer Feature
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
// create a new Product object
ProcessProduct(new Product
{
ProductID = ,
Name = "Kayak",
Description = "A boat for one person",
Price = 275M,
Category = "Watersports"
});
}
private static void ProcessProduct(Product prodParam)
{
//...statements to process product in some way
}
}
 Listing -. Initializing Collections and Arrays
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
string[] stringArray = { "apple", "orange", "plum" };
List<int> intList = new List<int> { , , , };
Dictionary<string, int> myDict = new Dictionary<string, int> {
{ "apple", },
{ "orange", },
{ "plum", }
};
}
}

3、Using Extension Methods

扩展方法,假设已有类ShoppingCart,在不修改这个类本身的情况下,如果要为它增加method,就可以使用扩展方法。扩展方法并不能打破ShoppingCart的封装性和对数据的访问规则,仍然是只能访问允许访问的数据,如public。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_11ExtensionMethod
{
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 { set; get; } } public class ShoppingCart
{
public List<Product> Products { get; set; }
} public static class MyExtensionMethods
{
public static decimal TotalPrices(this ShoppingCart cartParam)
{
decimal total = ;
foreach (Product prod in cartParam.Products)
{
total += prod.Price;
}
return total;
}
} class Program
{
static void Main(string[] args)
{
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}
}
};
decimal cartTotal = cart.TotalPrices();
Console.WriteLine("Total: {0:c}", cartTotal);
}
}
}

4、Applying an Extension Method to Different Implementations of the Same Interface

将扩展方法应用到接口上

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; namespace ExtensionMethodInterface
{
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 { set; get; }
} public class ShoppingCart : IEnumerable<Product>
{
public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} public static class MyExtensionMethods
{
public static decimal TotalPrices(this IEnumerable<Product> productEnum)
{
decimal total = ;
foreach (Product prod in productEnum)
{
total += prod.Price;
}
return total;
}
} class Program
{
static void Main(string[] args)
{
// create and populate ShoppingCart
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}
}
}; // create and populate an array of Product objects
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}
}; // get the total value of the products in the cart
decimal cartTotal = products.TotalPrices();
decimal arrayTotal = productArray.TotalPrices();
Console.WriteLine("Cart Total: {0:c}", cartTotal);
Console.WriteLine("Array Total: {0:c}", arrayTotal);
}
}
}

5、Using the Filtering Extension Method

使用带过滤器的扩展方法

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; //添加 namespace _5_15FilterExtensionMethod
{
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 { set; get; }
} public class ShoppingCart : IEnumerable<Product>
{
public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} public static class MyExtensionMethods //扩展方法类
{
public static IEnumerable<Product> FilterByCategory(
this IEnumerable<Product> productEnum, string categoryParam) //带过滤器的扩展方法
{
foreach (Product prod in productEnum)
{
if (prod.Category == categoryParam)
{
yield return prod;
}
}
}
} class Program
{
static void Main(string[] args)
{
// create and populate ShoppingCart
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}
}
};
foreach (Product prod in products.FilterByCategory("Soccer"))
{
Console.WriteLine("Name: {0}, Price {1:c}", prod.Name, prod.Price);
}
}
}
}

显示结果为:

Name: Soccer ball, Price $19.50
Name: Corner flag, Price $34.95

6、Using Lambda Expressions

(1)定义委托函数的方式

在扩展方法中使用委托来完成条件过滤。然后对每个要过滤的条件形成一个委托函数。要使用哪一个条件,就将该条件对应的委托函数作为参数装配到扩展方法上。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; //添加 namespace _5_19DelegateFunc
{
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 { set; get; }
} public class ShoppingCart : IEnumerable<Product>
{
public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator() //IEnumerator需要using System.Collections;
{
return GetEnumerator();
}
} public static class MyExtensionMethods //扩展方法类
{
public static IEnumerable<Product> Filter( //第一个参数前有this关键字是扩展方法,注意要放在扩展方法类当中
this IEnumerable<Product> productEnum, //第二个参数接收委托
Func<Product, bool> selectorParam )
{
foreach (Product prod in productEnum)
{
if (selectorParam(prod))
{
yield return prod;
}
}
}
} class Program
{
static void Main(string[] args)
{
// create and populate ShoppingCart
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";
}; //将委托函数装配到扩展方法Filter上,得到过滤后的结果
IEnumerable<Product> filteredProducts = products.Filter(categoryFilter);

foreach (Product prod in filteredProducts)
{
Console.WriteLine("Name: {0}, Price: {1:c}", prod.Name, prod.Price);
} }
}
}

在上面这种情形下,我们可以用委托中指定的任何条件来过滤Product对象了,但我们必须为我们希望的每个条件定义一个Func,这是不理想的。替代方法是使用lambda表达式,它以一种简洁的格式在委托中表达一个方法的实现部分。我们可以用它来替换我们的委托定义

(2)lambda表达式

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace _5_22LambdaExpression
{
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 { set; get; }
} public class ShoppingCart : IEnumerable<Product>
{
public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator() //IEnumerator需要using System.Collections;
{
return GetEnumerator();
}
} public static class MyExtensionMethods //扩展方法类
{
public static IEnumerable<Product> Filter( //第一个参数前有this关键字是扩展方法,注意要放在扩展方法类当中
this IEnumerable<Product> productEnum, //第二个参数接收委托
Func<Product, bool> selectorParam)
{
foreach (Product prod in productEnum)
{
if (selectorParam(prod))
{
yield return prod;
}
}
}
} class Program
{
static void Main(string[] args)
{
// create and populate ShoppingCart
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}
}
}; //用Lambda表达式代替委托函数的函数体
Func<Product, bool> categoryFilter = prod => prod.Category == "Soccer";
IEnumerable<Product> filteredProducts = products.Filter(categoryFilter);
//可以完全省略掉Func,将上面两句可以写成更紧凑的语法如下
//IEnumerable<Product> filteredProducts = products.Filter(prod =>
// prod.Category == "Soccer");
foreach (Product prod in filteredProducts)
{
Console.WriteLine("Name: {0}, Price: {1:c}", prod.Name, prod.Price);
} }
}
}

我们可以通过扩展lambda表达式组合多个过滤条件

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; namespace _5_22LambdaExpression
{
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 { set; get; }
} public class ShoppingCart : IEnumerable<Product>
{
public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator()
{
return Products.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator() //IEnumerator需要using System.Collections;
{
return GetEnumerator();
}
} public static class MyExtensionMethods //扩展方法类
{
public static IEnumerable<Product> Filter( //第一个参数前有this关键字是扩展方法,注意要放在扩展方法类当中
this IEnumerable<Product> productEnum, //第二个参数接收委托
Func<Product, bool> selectorParam)
{
foreach (Product prod in productEnum)
{
if (selectorParam(prod))
{
yield return prod;
}
}
}
} class Program
{
static void Main(string[] args)
{
// create and populate ShoppingCart
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}
}
}; //组合多个条件
IEnumerable<Product> filteredProducts = products.Filter(prod =>
prod.Category == "Soccer" || prod.Price > ); foreach (Product prod in filteredProducts)
{
Console.WriteLine("Name: {0}, Price: {1:c}", prod.Name, prod.Price);
} }
}
}

显示结果为:

Name: Kayak, Price $275.00
Name: Lifejacket, Price $48.95

Name: Soccer ball, Price $19.50
Name: Corner flag, Price $34.95

7、 OTHER FORMS FOR LAMBDA EXPRESSIONS

我们可以不必在Lambda表达式中直接表现委托逻辑。可以用调用另一个方法来实现,如下所示:

prod => EvaluateProduct(prod)

另外,如果我们需要用Lambda表达式来表示一个多参数的委托,我们可以把参数封装在在括号内,如下:

(prod, count) => prod.Price > 20 && count > 0

最后,如果Lambda表达式中的逻辑需要多条语句,我们可以用花括号括起来,并用一条返回语句来完成,如下:

(prod, count) =>

{

//...multiple code statements

return result;

}

8、Using Automatic Type Inference

Listing 5-23. Using Type Inference

     var myVariable = new Product { Name = "Kayak", Category = "Watersports", Price = 275M };
string name = myVariable.Name; // legal
int count = myVariable.Count; // compiler error

C#的var关键字允许你定义一个局部变量而不给它指定确切类型,这叫做类型推断(type inference),或者隐式类型推导(implicit typing)。(上面例子中的myVariable在定义时就没有明确指定类型,只是用var来定义)并不是myVariable没有类型,只是我们要求编译器从代码中来推断出它。可以在语句中看到,编译器只允许推断类(这里是Product)中的成员被调用。(所以myVariable.Name合法,而myVariable.Cout就会引起编译错误。)

9、Using Anonymous Types

通过结合对象初始化器(object initializers)和类型推断,我们可以创建一个简单数据存储对象(data-storage objects),而不需要定义相应的类或结构。(也就是说不事先定义类或结构,直接用new就生成对象。)

Listing 5-24. Creating an Anonymous Type

 var myAnonType = new {
Name = "MVC",
Category = "Pattern"
};
Console.WriteLine("Name: {0}, Type: {1}", myAnonType.Name, myAnonType.Category);

在这个例子中,myAnonType是一个匿名类型对象。这并不意味着它是动态的,JavaScript变量在这种情况下才是动态类型的。这只表示类型定义由编译器自动生成。强类型仍然是必须的。例如,你只可以获取和设置初始化器中已经定义的那些属性。

C#编译器基于初始化器中参数的名字和类型来生成这个类。有同样属性名和类型的两个匿名类型对象将被指派为自动生成的同样的类。意即,我们可以生成匿名类型对象的数组。

Listing 5-25. Creating an Array of Anonymously Typed Objects

 var oddsAndEnds = new[] {
new { Name = "MVC", Category = "Pattern"},
new { Name = "Hat", Category = "Clothing"},
new { Name = "Apple", Category = "Fruit"}
};
foreach (var item in oddsAndEnds) {
Console.WriteLine("Name: {0}", item.Name);
}

10、Performing Language Integrated Queries

Language Integrated Query简称LINQ。到目前为止,我们所描述的所有语言特性都可以很好地用在LINQ中。我们热爱LINQ。它是一种奇妙而奇怪的强制添加到.NET的功能。如果你还从没用过LINQ,你就已经出局了。LINQ通过类SQL的语法(SQL-like syntax)来在类中查询数据。假设我们有一个Product对象的集合,我们想找出价格最高的三个,并打印出名字和价格。没有LINQ,我们需要如表5-26所示来完成。

Listing 5-26. Querying Without LINQ

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_26WithoutLINQ
{
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
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}
}; // define the array to hold the results
Product[] results = new Product[]; // 对数组中元素排序,item1和item2参数位置在Sort和Compare中一致时表示升序
//Array.Sort(products, (item1, item2) =>
//{
// return Comparer<decimal>.Default.Compare(item1.Price, item2.Price);
//}); //item1和item2参数位置在Sort和Compare中相反时表示降序
//排序后数组元素中前三个为价格最高的3个产品
Array.Sort(products, (item1, item2) =>
{
return Comparer<decimal>.Default.Compare(item2.Price, item1.Price);
}); // get the first three items in the array as the results
//把数组products前3个元素拷贝到数组results中
Array.Copy(products, results, );
// print out the names
foreach (Product p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
}
}
}
}

显示结果为:

Item: kayak, Cost:275

Item: Lifejacket, Cost:48.95

Item: Corner flag, Cost:34.95

下面我们用LINQ来实现。

Listing 5-27. Using LINQ to Query Data

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_27UsingLINQ
{
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
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 = from product in products
orderby product.Price descending
select new {
product.Name,
product.Price
};
int count = ;
// print out the names
foreach (var p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
if (++count == )
{
break;
}
}
}
}
}

这要简洁得多,可以看到类SQL的查询。我们以降序对Product对象进行排序,并用关键字select返回只包含我们想要属性的匿名类型。LINQ的这种风格称为查询语法,是大多数开发人员所熟悉的。本例中这个查询的缺点是它将数组中的每个Product都返回到了一个匿名类型对象中。所以我们需要处理结果,以获得最开始的三个,并打印出来。

然而,如果我们愿意放弃上面这种查询语法的简单性,我们可以得到功能更强大的LINQ。可选用的方法是基于扩展方法(extension methods)的点号表示法语法,或者叫点号表示法。表5-28演示了这中科选方式来处理我们的Product对象。

Listing 5-28. Using LINQ Dot Notation

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_28DotNotation
{
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
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
.OrderByDescending(e => e.Price)
.Take()
.Select(e => new { e.Name, e.Price });
foreach (var p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
}
}
}
}

OrderByDescending方法重组数据源中的条目。这里,lambda表达式返回我们要用来比较的值。Take方法返回结果最前面(这是我们用查询语法不能实现的)的一个指定数目的条目。Select方法允许我们设计结果,指定我们想要的结果。这里,我们设计一个匿名对象,它包含了Name和Price属性。注意,我们甚至不需要指定匿名类型中的属性名。C#已经根据我们在Select方法中拾取的属性推断了这些名字。

表5-1描述了最有用的LINQ扩展方法。本书中我们到处都使用LINQ,当你看到一个以前还未遇见的扩展方法时,回过来查看此表可能是很有用的。表5-1所显示的所有LINQ方法都是在IEnumerable<T>上进行操作。

Table 5-1. Some Useful LINQ Extension Methods

Extension Method
扩展方法

Description
描述

Deferred
是否延迟

First

Returns the
first item from the data source
返回数据源的第一个条目

No

FirstOrDefault

Returns the
first item from the data source or the default value if there are no items
返回数据源的第一个条目,或者,如果无条目时,返回默认值

No

Last

Returns the
last item in the data source
返回数据源的最后一个条目

No

LastOrDefault

Returns the
last item in the data source or the default value if there are no items
返回数据源的最后条目,或无条目时返回默认值

No

Max

Min

Returns the
largest or smallest value specified by a lambda expression
返回由lambda表达式表示的最大值或最小值

No

OrderBy

OrderByDescending

Sorts the
source data based on the value returned by the lambda expression
根据lambda表达式基于返回值进行排序

Yes

Reverse

Reverses the
order of the items in the data source
倒序排列数据源中的条目顺序

Yes

Select

Projects a
result from a query
设计一个查询结果

Yes

SelectMany

Projects each
data item into a sequence of items and then concatenates all of those
resulting sequences into a single sequence
把每个数据条目投射到一个条目序列之中,然后把所有这些结果序列连接成一个序列

Yes

Single

Returns the
first item from the data source or throws an exception if there are multiple
matches
返回数据源的第一个适配项,如果有多个匹配则抛出一个异常

No

SingleOrDefault

Returns the
first item from the data source or the default value if there are no items,
or throws an exception if there are multiple matches
返回数据源的第一个条目,或都没条目时返回默认值,或者有多个条目时返回一个异常

No

Skip

SkipWhile

Skips over a
specified number of elements, or skips while the predicate matches
跳过指定数目的元素,或者当谓词匹配时跳过

Yes

Sum

Totals the
values selected by the predicate
总和谓词选定的值

No

Take

TakeWhile

Selects a
specified number of elements from the start of the data source or selects
items while the predicate matches
从数据源的开始处选择指定数目的元素,或当谓词匹配时选择指定数目的条目

Yes

ToArray

ToDictionary

ToList

Converts the
data source to an array or other collection type
把数据源转换成数组或其它集合类型

No

Where

Filters items
from the data source that do not match the predicate
过滤掉源数据中与谓词不匹配的条目

Yes

11、Understanding Deferred LINQ Queries

你可能注意到表5-1中最后一列是”延迟”(Deferred)。扩展方法在LINQ查询中执行时有一个有趣的变异。含有deferred方法的查询要直到IEnumerable<T>结果中的条目被枚举时才会执行,如列表5-29所示

Listing 5-29. Using Deferred LINQ Extension Methods in a Query

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_29 DeferredLINQ
{
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
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
.OrderByDescending(e => e.Price)
.Take()
.Select(e => new { e.Name, e.Price });
products[] = new Product{ Name=”Stadium”, Price=79500M };
foreach (var p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
}
}
}
}

OrderByDescending扩展方法是延迟的,也就是虽然定义好了查询,但是要等到枚举的时候才执行。所以本例中,通过products[2] = new Product{ Name=”Stadium”, Price=79500M };来修改了product[2],最后枚举的时候才执行查询,结果为:

Item: Stadium, Cost: 79500

Item: Kayak, Cost: 275

Item: Lifejacket, Cost: 48.95

你可以看到,直到结果被枚举时,才会评估这个查询,因此,我们所做的修改 — 把Stadium引入到Product数组 — 会反映在输出中。相比之下,用任何无deferred扩展方法都会使LINQ查询立即执行。列表5-30提供了一个演示。

Listing 5-30. An Immediately Executed LINQ Query

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_30 ImmediatelyExecutedLINQ
{
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
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[] = new Product{ Name=”Stadium”, Price=79500M };
foreach (var p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
}
}
}
}

因为立即执行,所以后面的修改就影响不到最后的结果了。结果为:

Sum: $378.40

12、Repeatedly Using a Deferred Query

有延迟的LINQ扩展方法引起的一个有趣特性是每次枚举结果时都是从头开始。

Listing 5-31. Repeatedly Executing a Deferred Query

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace _5_31 RepeatedlyDeferredLINQ
{
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 { set; get; }
} class Program
{
static void Main(string[] args)
{
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
.OrderByDescending(e => e.Price)
.Take()
.Select(e => new { e.Name, e.Price });
foreach (var p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
} Console.WriteLine("---End of results---");
products[] = new Product{ Name=”Stadium”, Price=79500M };
foreach (var p in results)
{
Console.WriteLine("Item: {0}, Cost: {1}", p.Name, p.Price);
}
}
}
}

这个例子创建了数据,定义了具有延迟的LINQ查询,然后枚举查询结果。之后,其中一个数组元素被修改,再重新枚举查询结果。显示结果为:

Item: Kayak, Cost: 275

Item: Lifejacket, Cost: 48.95

Item: Corner flag, Cost: 34.95

---End of results---

Item: Stadium, Cost: 79500

Item: Kayak, Cost: 275

Item: Lifejacket, Cost: 48.95

---End of results--

相关文章