LINQ 介绍

1. 简介

LINQ是.NET framework 3.5的新特性,其全称是 Language Integrated Query,是指将查询功能和语言结合起来。LINQ按其查询的数据源可以分为三种,分别是 LINQ to XML, LINQ to ADO.NET和LINQ to Objects。其中 LINQ to ADO.NET又可以分为LINQ to DataSet,LINQ to SQL 和 LINQ to Entities。LINQ to Object 是其它的基础,在C#内部,所有的LINQ查询最终都是被解释成 LINQ to Object的,所以下面先介绍 LINQ to Object。

先来看一个简单的例子:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace FirstLINQ

{

class Program

{

static void Main()

{

int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

var numQuery =

from num in numbers

where (num % 2) == 0

select num;

foreach (var num in numQuery)

Console.Write("{0,1} ", num);

Console.ReadLine();

}

}

}

关键的部分就是from…in…where…select,这个本质上和标准的SQL语句select…from…where… 是一个意思。上面的程序的输出就是:

0 2 4 6.

为了彻底理解LINQ的语法,先介绍下C#语言的新特性。

1. var 关键字

var是C# 3.0的新关键字,它表示声明一个类型能够隐式确认的变量,例如:

var i = 10; // implicitly typed

int i = 10; //explicitly typed

再看一个msdn的例子:

// Example #1: var is optional because

// the select clause specifies a string

string[] words = { "apple", "strwawberry", "grape", "peach", "banana" };

var wordQuery = from word in words

where word[0] == 'g'

select word;

// Because each element in the sequence is a string,

// not an anonymous type, var is optional here also.

foreach (string s in wordQuery)

{

Console.WriteLine(s);

}

// Example #2: var is required because

// the select clause specifies an anonymous type

var custQuery = from cust in customers

where cust.City == "Phoenix"

select new { cust.Name, cust.Phone };

// var must be used because each item

// in the sequence is an anonymous type

foreach (var item in custQuery)

{

Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);

}

2. Auto-Implemented Properties

对于某些仅需要进行读写操作的简单属性,可以使用自动完成的属性,以减少编码的工作量,例如:

class LightweightCustomer

{

public LightweightCustomer(double total, string name, int id)

{

this.Name = name;

this.CustomerID = id;

this.TotalPurchases = total;

}

public double TotalPurchases { get; set; }

public string Name { get; private set; } // read-only

public int CustomerID { get; private set; } // read-only

}

class Program

{

static void Main(string[] args)

{

LightweightCustomer cus = new LightweightCustomer(12.4, "new C#", 1);

Console.WriteLine("{0} {1} {2}", cus.CustomerID, cus.Name, cus.TotalPurchases);

}

}

C#编译器会自己建立一个内部的字段。

3 Extension Method

Extension Method 本身是一个静态类的方法,但是它允许一个对象像调用该对象自己的方法一样调用它。Extension Method的声明方法是在第一个参数前面加上 this 关键字,这个参数就是调用这个方法的对象。

例如:

public static class Extensions

{

public static int ToInt32(this string s)

{

return Int32.Parse(s);

}

}

然后就可以这样来调用:

string s = "123";

int i = s.ToInt32();

Extension Method 中可以使用泛型。例如:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace UnderstandGenericsAssumption

{

class Program

{

static void Main(string[] args)

{

GenericTypeResolverTest v = new GenericTypeResolverTest();

v.Value = "TEST";

v.Test();

}

}

//generic implicit type resolver.

public class GenericTypeResolverTest {

public string Value { get; set; }

public override string ToString() {

return Value.ToString();

}

}

public static class GenericTypeResolverMethodTest {

public static void Test<T>(this T obj) {

Console.WriteLine(obj.ToString());

}

}

}

一般在使用泛型方法的时候,必须指明类型,例如:

static void Swap<T>(ref T lhs, ref T rhs)

{

T temp;

temp = lhs;

lhs = rhs;

rhs = temp;

}

public static void TestSwap()

{

int a = 1;

int b = 2;

Swap<int>(ref a, ref b);

System.Console.WriteLine(a + " " + b);

}

但是在Extension Method中,C#可以自动推演泛型类型的真正类型。

4.Lambda 表达式

Lambda表达式可以认为是匿名委托的更简略的写法。Lambda表达式都使用=>运算符,表示将其左边的输入运算为其右边的表达式。例如:

a => a == "test";

一个Lambda表达式都可以赋值给一个委托,例如,msdn的例子:

delegate int del(int i);

del myDelegate = x => x * x;

int j = myDelegate(5); //j = 25

LINQ查询语句中的where实际上是一个Extension Method,位于System.Linq.Enumerable 类中,其声明如下:

public static IEnumerable<TSource> Where<TSource>(

this IEnumerable<TSource> source,

Func<TSource, bool> predicate

)

其中 Func是一个委托:

public delegate TResult Func<T, TResult>(

T arg

)

这个委托表示接受一个类型为T的参数返回类型为Tresult的一类函数,是一个一元运算符,这一类函数特别适合要对序列中每一个对象实行某种操作的情况。Lambda表达式也可以作为参数传给以Func<T,TResult> 为参数类型的函数,例如:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace UnderstandLambda

{

class Program

{

static void Main(string[] args)

{

var lists = new string[] { "code6421", "tom", "david" };

var result = lists.Where(a => a.MyContains("2"));

// var result = from s1 in lists where s1.MyContains("code") select s1;

foreach (var item in result)

Console.WriteLine(item);

Console.ReadLine();

}

}

public static class MyExtensionMethod

{

public static bool MyContains(this string a,string matchs)

{

return a.Contains(matchs);

}

}

}

输出的结果是:code6421

Lambda表达式可以带有多个参数,例如:

(x, y) => x == y;

或者当类型不能确定的时候,可以明确指定:

(int x, string s) => s.Length > x;

也可以没有参数:

() => SomeMethod();

也可以包括多条语句:

delegate void TestDelegate(string s);

TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };

myDel("Hello");

5. Object and Collection Initializers

Object Initializer可以在构造一个对象时直接指定其可读的属性,而不需要调用明确的构造函数,这样主要可以减少编码的工作量,例如:

private class Cat

{

// Auto-implemented properties

public int Age { get; set; }

public string Name { get; set; }

}

static void MethodA()

{

// Object initializer

Cat cat = new Cat { Age = 10, Name = "Sylvester" };

}

Collection Initializer与此是类似的,可以在初始化一个集合对象的时候直接指定他的值:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };

或者:

List<Cat> cats = new List<Cat>

{

new Cat(){ Name="Sylvester", Age=8 },

new Cat(){ Name="Whiskers", Age=2},

new Cat() { Name="Sasha", Age=14}

};

2 Linq Query Expression 详解

有了上面的准备就可以详细介绍 Linq Query Expression了。它的一般形式如下:

from <alias> in <expression(datasource)> <where-expression> | <group expression> | <join-expression> | <order-by-expression> |

<select-expression>

Linq Query Expression 实际上都由编译器转化为函数调用,这些调用的函数都是Extension Method,位于 System.Linq.Enumerable 命名空间中。这些函数基本上都是对IEnumerable<T>进行的操作的,也就是说Linq to Objects实际上是对于IEnumerable<T>类型的对象实行查找、筛选等操作。下面的方法可以用于Linq Query Expression中,自然也可以用于通常的IEnumerable<T>对象。

2.1 嵌套Query Expression

其中<expression(datasource)> 是数据来源,可以是一个IEnumerable接口的对象,也可以是子查询。例如:

int[] numbers = { 0, 3, 4, 5, 6, 7, 8, 13, 16 };

var num= from num1 in (from s in numbers where s>4 select s)

where num1%2==0 select num1;

foreach(var n in num)

Console.Write("{0 }",n);

输出结果为 6 8 16。

通常使用var来让编译器决定Query Expression的返回值,实际上,大多数情况下,Query Expression是返回的IEnumerable<T>类型,例如,上面的例子可以改写为:

IEnumerable<Int32> num= from num1 in (from s in numbers where s>4 select s)

where num1%2==0 select num1;

例外是当使用了First()之类的函数的时候,返回的就是T类型的对象本身,这一类函数同样定义正在System.Linq.Enumerable类中。因此,Query Expression 可以嵌套是很自然的。

2.2 where 子句

where 子句的使用比较简单,可以通过where子句来筛选所需要的数据。也可以自定义自己的函数来实现类似于like的功能,上面介绍Lambda语句的使用已经有一个例子,事实上,由于可以自定义函数,where子句所能实现的功能远比like强。

2.3 group 子句

group子句用于将数据分组,group子句返回的是实现如下接口的对象的序列:

public interface IGrouping<TKey, TElement> : IEnumerable<TElement>,

IEnumerable

也就是:IEnumerable<IGrouping<TKey, TElement>>的对象,本质上是一个链表的链表。

IGrouping 接口本身实现了 IEnumerable接口,但是它还有一个类型为TKey的键,用来标识用来分组的数据项。他有一个只读的属性,Tkey Key,可以获得这个键。例如:

private static void TestGroupByLinq()

{

Person[] persons = new Person[]{

new Person{Name="code6421",Age=18,Address="Taipen"},

new Person{Name="jeffray",Age=18,Address="USA"},

new Person{Name="catch",Age=12,Address="USA"},

new Person{Name="joe",Age=18,Address="TY"}};

var p = from o in persons group o by o.Address into g select new { Address = g.Key, Persons = g };

foreach (var s in p)

{

Console.WriteLine("Group : {0}", s.Address);

foreach (var s1 in s.Persons)

Console.WriteLine(s1.Name);

}

Console.ReadLine();

}

输出的结果是:

Group : Taipen

code6421

Group : USA

jeffray

catch

Group : TY

Joe

其中的into 子句表示把结果集存到一个变量g中,最后的select 子句可以选择需要的列,new 的语法是使用了匿名类。

2.4 join 子句

join 子句与SQL语句的join是一样的,用于将多张表连接起来,下面是一个范例:

private static void TestJoin()

{

var p1 = new[]{new {Name = "code6421", Address = "Taipen"},

new {Name = "tom", Address = "Taipen"},

new {Name = "jeffray", Address = "NY"}};

var p2 = new[]{new {Name = "code6421", Title = "Manager"},

new {Name = "tom", Title = "Director"},

new {Name = "jeffray", Title = "Programmer"}};

var p3 = from s in p1

join s1 in p2 on s.Name equals s1.Name

select new { Name = s.Name, Address = s.Address, Title = s1.Title };

foreach (var v in p3)

Console.WriteLine("Name {0}, Address {1}, Title {2}", v.Name, v.Address, v.Title);

}

输出的结果是:

Name code6421, Address Taipen, Title Manager

Name tom, Address Taipen, Title Director

Name jeffray, Address NY, Title Programmer

2.5 orderby 子句

private static void TestOrderLinq()

{

string[] list = new string[] { "1111", "2222", "3333" };

var p = from o in list orderby o descending select o;

foreach (var s in p)

Console.WriteLine(s);

}

输出的结果是:3333 2222 1111

descending表示降序,ascending表示升序。

2.6 Distinct 方法

Distinct方法可以从一个结果集中选择出不重复的一部分,例如:

private static void TestSelectDistinct()

{

var p1 = new[]{ new {Name = "code6421", Age=18, Address = "Taipen"},

new {Name = "cathy", Age=18, Address = "Taipen"},

new {Name = "tom", Age=18, Address = "NY"}};

var p2 = (from s in p1 select s.Address).Distinct();

foreach (var p4 in p2)

Console.WriteLine(p4);

}

结果是:

Taipen

NY

Distinct方法也可以接受一个实现IEqualityComparer<T>接口的对象,来实现自定义的对象比较,例如:

private static void TestSelectDistinctWithCondition()

{

var p1 = new Person[]{ new Person(){Name = "code6421", Age=18, Address = "Taipen"},

new Person(){Name = "cathy", Age=18, Address = "Taipen"},

new Person(){Name = "tom", Age=18, Address = "NY"}};

var p2 = (from s in p1 select s).Distinct(new MyObjectComparer<Person>() { PropertyName = "Address" });

foreach (var p4 in p2)

Console.WriteLine(p4.Name);

}

其中MyObjectComparer类定义如下:

public sealed class MyObjectComparer<T> : IEqualityComparer<T>

{

public string PropertyName { get; set; }

#region IEqualityComparer<T> Members

public bool Equals(T x, T y)

{

if (x == null && y == null) return true;

if (x == null && y != null ||

x != null && y == null) return false;

PropertyInfo pi1 = x.GetType().GetProperty(PropertyName);

return pi1.GetValue(x, null).Equals(pi1.GetValue(y, null));

}

public int GetHashCode(T obj)

{

if (obj == null) return -1;

PropertyInfo pi = obj.GetType().GetProperty(PropertyName);

object v1 = pi.GetValue(obj, null);

if (v1 == null) return -1;

return v1.GetHashCode();

}

#endregion

}

这个类利用反射,实现了根据某个特定的属性来判断连个对象是否相等。

2.7 Take,TakeWhile 方法

Take函数可以从IEnumerable<T>对象中取出特定个数的元素,类似于 T-SQL中的top子句;TakeWhile方法允许根据某一条件筛选出元素,直至第一个不满足条件的元素为止。

private static void TestTake()

{

var p1 = new[]{ new {Name = "code6421", Age=18, Address = "Taipen"},

new {Name = "cathy", Age=18, Address = "Taipen"},

new {Name = "tom", Age=18, Address = "NY"}};

var p3 = (from s1 in p1 select s1).Take(2);

foreach (var p4 in p3)

Console.WriteLine(string.Format("Name {0}, Title {1}", p4.Name, p4.Address));

}

运行结果是:

Name code6421, Title Taipen

Name cathy, Title Taipen

TakeWhile方法的声明如下:

public static IEnumerable<TSource> TakeWhile<TSource>(

this IEnumerable<TSource> source,

Func<TSource, bool> predicate

)

使用方法是:

var p3 = (from s1 in p1 select s1).TakeWhile(x => x.Address == "Taipen");

这样输出结果就是:

Name code6421, Title Taipen

Name cathy, Title Taipen

注意如果筛选条件改为 x => x.Address == "NY",将不输出任何元素,因为列表中第一个元素就不符合条件。

与这两个方法类似的方法还有Skip和SkipWhile方法,他们是跳过相应的元素。

2.8First 和 FirstOrDefault方法

First方法返回IEnumerable对象中的第一个元素,也可以返回符合某一条件的第一个元素,如果第一个元素不存在则抛出异常;FirstOrDefault方法是和First一样的,只是当第一个元素不存在的时候不抛出异常而是返回该类型的默认值。例如:

private static void TestFirst()

{

var p1 = new[]{ new {Name = "code6421", Age=18, Address = "Taipen"},

new {Name = "cathy", Age=18, Address = "Taipen"},

new {Name = "tom", Age=18, Address = "NY"},

new {Name = "tom2", Age=18, Address = "NY"}};

var p3 = (from s1 in p1 select s1).First();

Console.WriteLine(string.Format("Name {0}, Address {1}", p3.Name, p3.Address));

}

运行结果是:

Name code6421, Address Taipen

也可以这样:

var p3 = (from s1 in p1 select s1).First(x => x.Address == "NY");

运行结果是:

Name tom, Address NY

与这两个对应的方法有 Last和LastOrDefault。

2.9 Any方法

Any方法可以判断IEnumerable对象中是否含有元素或者是否含有满足某一条件的元素。例如:

private static void TestAny()

{

var numbers = new[] { 5, 6, 7, 8 };

var numbers2 = new int[0];

if (numbers.Any())

Console.WriteLine("numbers has element");

if (numbers2.Any())

Console.WriteLine("numbers2 has element");

}

输出的结果是:

numbers has element

private static void TestAnyWithCondition()

{

var numbers = new[] { 5, 6, 7, 8 };

if (numbers.Any( x => x > 7))

Console.WriteLine("numbers has some elements greater than 7");

}

输出的结果是:

numbers has some elements greater than 7

与这个函数用法类似的方法还有All,Contains 方法,分别用来判断是否所有的元素都满足某一条件和是否包含某一特定的元素。

2.10 Reverse方法

Reverse方法就是将一个对象中的元素进行反转操作。例如:

private static void TestReverse()

{

var numbers = new[] { 8, 9, 10 };

var result = numbers.Reverse();

foreach (var item in result)

Console.WriteLine(item);

}

输出的结果是:10 9 8

2.11 Concat方法

Concat方法将两个对象中的元素合并到一个元素中去:

private static void TestConcat()

{

var numbers = new[] { 8, 9, 10 };

var numbers2 = new[] { 7, 8, 9, 10, 6 };

var result = numbers.Concat(numbers2);

foreach (var item in result)

Console.WriteLine(item);

}

输出的结果是:

8 9 10 7 8 9 10 6

2.12 ToArray,ToList,ToDictionary方法

这三个方法将IEnumerable<T>对象转换成Array,List或者是Dictionary类型。默认情况下,当我们对某个IEnumerable<T>对象下达where等条件式的时候,所取得结果是IEnumerable<T>对象,此时尚未对该对象中的元素执行比对的操作,仅当通过此IEnumerable<T>对象取得Enumerator对象明确调用MoveNext函数的时候才会逐个比对,此模式不仅适用于Linq to Object,其它的Linq也是这样的。但是,调用这三个方法以后,会对此对象中每一个元素执行比对,仅仅返回符合条件的元素,这样得到的对象会比较小。

ToArray的声明是:

public static TSource[] ToArray<TSource>(

this IEnumerable<TSource> source

)

例如:

private static void TestToArray()

{

var p1 = new[]{ new {Name = "code6421", Age=18, Address = "Taipen"},

new {Name = "cathy", Age=18, Address = "Taipen"},

new {Name = "tom", Age=18, Address = "NY"}};

var p3 = (from s1 in p1 select s1).ToArray();

foreach (var item in p3)

Console.WriteLine(item.Name);

}

输出的结果是:

code6421

cathy

tom

ToList方法和这个是类似的,只是返回一个List<T>对象而不是数组。

ToDictionary方法稍稍复杂一些,一共有4个重载方法:

public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(

this IEnumerable<TSource> source,

Func<TSource, TKey> keySelector

)

这个方法接受一个keySelector参数,这个参数的作用是从一个元素中抽取出作为键的字段,例如:

private static void TestToDictionary()

{

var p1 = new[]{ new {Name = "code6421", Age=18, Address = "Taipen"},

new {Name = "cathy", Age=18, Address = "Taipen"},

new {Name = "tom", Age=18, Address = "NY"}};

var p3 = (from s1 in p1 select s1).ToDictionary(x => x.Name);

foreach (var p4 in p3)

{

Console.WriteLine("Key {0}", p4.Key);

Console.WriteLine("Name {0}", p4.Value.Address);

}

}

运行结果是:

Key code6421

Name Taipen

Key cathy

Name Taipen

Key tom

Name NY

如果集合中有相同的键值,则会抛出异常 System.ArgumentException: An item with the same key has already been added.

public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(

this IEnumerable<TSource> source,

Func<TSource, TKey> keySelector,

IEqualityComparer<TKey> comparer

)

这个方法和上一个是一样的,只是可以自定义键判等的方式。

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(

this IEnumerable<TSource> source,

Func<TSource, TKey> keySelector,

Func<TSource, TElement> elementSelector

)

这个方法不仅可以指定哪个字段作为键,还可以知道哪个字段作为值,例如:

var p3 = (from s1 in p1 select s1).ToDictionary(x => x.Name,x=>x.Age);

foreach (var p4 in p3)

{

Console.WriteLine("Key {0}", p4.Key);

Console.WriteLine("Value {0}", p4.Value);

}

运行结果是:

Key code6421

Value 18

Key cathy

Value 18

Key tom

Value 18

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(

this IEnumerable<TSource> source,

Func<TSource, TKey> keySelector,

Func<TSource, TElement> elementSelector,

IEqualityComparer<TKey> comparer

)

同样地,可以指定键判等的方式。

2.14 ToLookup 方法

Lookup 是System.Linq中的一个类,其声明如下:

public class Lookup<TKey, TElement> : ILookup<TKey, TElement>,

IEnumerable<IGrouping<TKey, TElement>>, IEnumerable

ILookup接口的声明如下:

public interface ILookup<TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>>, IEnumerable

ILookup接口表示的是一个可重复的词典,也就是每一个键可以映射到多个值。Lookup类实现了ILookup接口,实际上就是一个IGrouping的集合:IEnumerable<IGrouping<TKey,TElement>>. ToLookup也是一种对数据分组的方法。下面是一个使用Lookup的例子:

class Package

{

public string Company;

public double Weight;

public long TrackingNumber;

}

public static void LookupExample()

{

// Create a list of Packages to put into a Lookup data structure.

List<Package> packages = new List<Package> { new Package { Company = "Coho Vineyard", Weight = 25.2, TrackingNumber = 89453312L },

new Package { Company = "Lucerne Publishing", Weight = 18.7, TrackingNumber = 89112755L },

new Package { Company = "Wingtip Toys", Weight = 6.0, TrackingNumber = 299456122L },

new Package { Company = "Contoso Pharmaceuticals", Weight = 9.3, TrackingNumber = 670053128L },

new Package { Company = "Wide World Importers", Weight = 33.8, TrackingNumber = 4665518773L } };

// Create a Lookup to organize the packages. Use the first character of Company as the key value.

// Select Company appended to TrackingNumber for each element value in the Lookup.

Lookup<char, string> lookup = (Lookup<char, string>)packages.ToLookup(p => Convert.ToChar(p.Company.Substring(0, 1)),

p => p.Company + " " + p.TrackingNumber);

// Iterate through each IGrouping in the Lookup and output the contents.

foreach (IGrouping<char, string> packageGroup in lookup)

{

// Print the key value of the IGrouping.

Console.WriteLine(packageGroup.Key);

// Iterate through each value in the IGrouping and print its value.

foreach (string str in packageGroup)

Console.WriteLine(" {0}", str);

}

// This code produces the following output:

// C

// Coho Vineyard 89453312

// Contoso Pharmaceuticals 670053128

// L

// Lucerne Publishing 89112755

// W

// Wingtip Toys 299456122

// Wide World Importers 4665518773

// Get the number of key-collection pairs in the Lookup.

int count = lookup.Count;

// Select a collection of Packages by indexing directly into the Lookup.

IEnumerable<string> cgroup = lookup['C'];

// Output the results.

Console.WriteLine("\nPackages that have a key of 'C':");

foreach (string str in cgroup)

Console.WriteLine(str);

// This code produces the following output:

// Packages that have a key of 'C'

// Coho Vineyard 89453312

// Contoso Pharmaceuticals 670053128

// Determine if there is a key with the value 'G' in the Lookup.

bool hasG = lookup.Contains('G');

}

2.15 Union 、Intersect 和 Except 方法

Union方法可以将两个IEnumerable对象中的元素并成一个,并且仅保留不同的元素;Intersect方法是保留两个IEnumerable对象中都有的元素;Except除去第一个IEnumerable中也存在于第二个IEnumerable对象中的元素。这三个方法对应于数学上集合的并,交和差的运算。

private static void TestUnion()

{

var p1 = new int[] { 1, 3, 5, 7, 9, 11 };

var p2 = new int[] { 2, 4, 6, 8, 10, 11 };

var p3 = from s in p1 select s;

var p4 = from s in p2 select s;

var p5 = p3.Union(p4);

var p6 = p3.Intersect(p4);

foreach (var i in p5)

Console.Write("{0} ", i);

Console.WriteLine();

foreach (var i in p6)

Console.Write("{0} ", i);

}

运行结果如下:

1 3 5 7 9 11 2 4 6 8 10

11

2.16 Sum,Average,Min,Max,Count

这几个函数提供Sql语言中聚合函数的功能,使用方法都是类似的,也比较简单,仅举一例:

private static void TestSum1()

{

var p1 = new[] { 18, 20, 25 };

var p3 = p1.Sum();

Console.WriteLine(p3);

}

运行结果是:

63

2.17 Aggerate方法

Aggerate方法提供更加一般的累加方法,其定义如下:

public static TSource Aggregate<TSource>(

this IEnumerable<TSource> source,

Func<TSource, TSource, TSource> func

)

这里的Func的定义如下:

public delegate TResult Func<T1, T2, TResult>(

T1 arg1,

T2 arg2

)

表示一个二元运算符。

例如:

private static void TestAggregate()

{

var p1 = new[] { 18, 20, 25 };

var p3 = p1.Aggregate((x, y) => x * y);

Console.WriteLine(p3);

}

输出结果是:

9000.

也就是 18×20×25=9000.

2.18 let 子句

let子句可以让表达式的结果暂存于一个变量中,交给下面的表达式处理,例如:

private static void UseLet()

{

string[] list = new string[] { "Code6421 Huang", "Tom Do", "Cathy Chang" };

var result = from s1 in list

let words = s1.Split(' ')

from word in words

let w = word.ToLower()

where w[0] == 'c'

select word;

foreach (var item in result)

Console.WriteLine(item);

}

运行结果是:

Code6421

Cathy

Chang

3 LINQ to XML

LINQ to XML 提供一种全新的处理XML文档的方式,使得处理XML更加简单直观。支持Linq to XML的类位于 System.Xml.Linq命名空间中.

3.1 创建XML文档

下面的程序展示了如何创建一个XML文档:

static void CreateXml()

{

XDocument doc = new XDocument(new XElement("Customers",

new XElement("Customer",

new XAttribute("ID", "A0001"),

new XAttribute("Name", "Tom"),

new XAttribute("Address", "Taipen")),

new XElement("Customer",

new XAttribute("ID", "A0002"),

new XAttribute("Name", "Mary"),

new XAttribute("Address", "LD")),

new XElement("Customer",

new XAttribute("ID", "A0003"),

new XAttribute("Name", "Jeff"),

new XAttribute("Address", "YW"))));

doc.Save("customers.xml");

}

这样就生成了一个customers.xml文件,文件内容如下:

<?xml version="1.0" encoding="utf-8"?>

<Customers>

<Customer ID="A0001" Name="Tom" Address="Taipen" />

<Customer ID="A0002" Name="Mary" Address="LD" />

<Customer ID="A0003" Name="Jeff" Address="YW" />

</Customers>

创建的过程是很明了的,System.Xml.Linq命名空间中有很多类,可以和XML中的概念对应起来,例如:XML文档用XDocument类表示,XML文档中的元素用XElement类表示,元素的属性用XAttribute类表示,Xtext表示一个text结点等等。具体可以参考msdn中System.Xml.Linq的文档。

3.2 读取XML文档

下面的程序展示了如何读取一个XML文档:

static void ReadXml()

{

XDocument doc = XDocument.Load("customers.xml");

foreach (XElement elem in doc.Elements("Customers").Descendants("Customer"))

Console.WriteLine(string.Format("Customer ID : {0}, Name : {1}, Address : {2}", elem.Attribute("ID").Value, elem.Attribute("Name").Value, elem.Attribute("Address").Value));

Console.ReadLine();

}

转载于:https://www.cnblogs.com/yinzixin/archive/2009/09/23/1572881.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值