The Sixth Assignment
今天我们来学习一下LINQ这个神奇的东西。。。还有LINQ相关的一些玩意。。
根据度娘的说法:
LINQ,语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展。
它允许编写C#或者Visual Basic代码以查询数据库相同的方式操作内存数据。
LINQ定义了大约40个查询操作符,如select、from、in、where以及order by
LINQ 提供了一条更常规的途径即给.Net Framework添加一些可以应用于所有信息源的具有多种用途的语法查询特性
这是比向开发语言和运行时添加一些关系数据特性或者类似 XML 特性更好的方式。
这些语法特性就叫做 .NET Language Integrated Query (LINQ)
首先来学习一下LINQ相关的东西
1) from 临时变量 in 实现IEnumerable<T>接口的对象
IEnumerable和IEnumerable<T>接口在.NET中是非常重要的接口,它允许开发人员定义foreach语句功能的实现并支持非泛型方法的简单的迭代。
IEnumerable和IEnumerable<T>接口是.NET Framework中最基本的集合访问器。
来看一段代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace IEnumeratorSample { class Person //定义一个Person类 { public string Name; //定义Person的名字 public string Age; //定义Person的年龄 public Person(string name, string age) //为Person初始化(构造函数) { Name = name; //配置Name值 Age = age; //配置Age值 } }
}
上述代码定义了一个Person类并抽象一个Person类的属性,这些属性包括Name和Age。Name和Age属性分别用于描述Person的名字和年龄,用于数据初始化。
初始化之后的数据就需要创建一系列Person对象,通过这些对象的相应属性能够进行对象的访问和遍历,示例代码如下所示。
class Program
{ static void Main(string[] args) { Person[] per = new Person[2] //创建并初始化2个Person对象 { new Person("guojing","21"), //通过构造函数构造对象 new Person("muqing","21"), //通过构造函数构造对象 }; foreach (Person p in per) //遍历对象 Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age); Console.ReadKey(); }
}
上述代码创建并初始化了2个Person对象,并通过foreach语法进行对象的遍历。
但是上述代码是在数组中进行查询的,就是说如果要创建多个对象,则必须创建一个对象的数组,如上述代码中的Per变量,而如果需要直接对对象的集合进行查询,却不能够实现查询功能。
例如增加一个构造函数,该构造函数用户构造一组Person对象,示例代码如下所示。
private Person[] per; public Person(Person[] array) //重载构造函数,迭代对象 { per = new Person[array.Length]; //创建对象 for (int i = 0; i < array.Length; i++) //遍历初始化对象 { per[i] = array[i]; //数组赋值 } }
上述构造函数动态的构造了一组People类的对象,那么应该也能够使用foreach语句进行遍历,示例代码如下所示。
Person personlist = new Person(per); //创建对象 foreach (Person p in personlist) //遍历对象 { Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age); }
在上述代码的foreach语句中,直接在Person类的集合中进行查询,系统则会报错“ConsoleApplication1.Person”不包含“GetEnumerator”的公共定义,
因此foreach语句不能作用于“ConsoleApplication1.Person”类型的变量,因为Person类并不支持foreach语句进行遍历。
为了让相应的类能够支持foreach语句执行遍历操作,则需要实现派生自类IEnumerable并实现IEnumerable接口,示例代码如下所示。
public IEnumerator GetEnumerator() //实现接口 { return new GetEnum(_people); }
为了让自定义类型能够支持foreach语句,则必须对Person类的构造函数进行编写并实现接口,示例代码如下所示。
class Person:IEnumerable //派生自IEnumerable,同样定义一个Personl类 { public string Name; public string Age; public Person(string name, string age) { Name = name; Age = age; } public IEnumerator GetEnumerator() { return new PersonEnum(per); } }
上述代码重构了Person类并实现了接口,接口实现的 class PersonEnum : IEnumerator
{ public Person[] _per; int position = -1; public PersonEnum(Person[] list) { _per = list; } public bool MoveNext() //实现向前移动 { position++; //位置增加 return (position < _per.Length); //返回布尔值 } public void Reset() //位置重置 { position = -1; //重置指针为-1
} public object Current { get { return _per[position]; }
}
上述代码实现了foreach语句的功能,当开发Person类初始化后就可以直接使用Personal类对象的集合进行LINQ查询,示例代码如下所示。
static void Main(string[] args) { Person[] per = new Person[2] { new Person("guojing","21"), new Person("muqing","21"), }; Person personlist = new Person(per); foreach (Person p in personlist) Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age); Console.ReadKey(); }
实例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace IEnumeratorSample { class Person : IEnumerable { public string Name; public string Age; public Person(string name, string age) { Name = name; Age = age; } private Person[] per; public Person(Person[] array) { per = new Person[array.Length]; for (int i = 0; i < array.Length; i++) { per[i] = array[i]; } } public IEnumerator GetEnumerator() { return new PersonEnum(per); } } class PersonEnum : IEnumerator { public Person[] _per; int position = -1; public PersonEnum(Person[] list) { _per = list; } public bool MoveNext() { position++; return (position < _per.Length); } public void Reset() { position = -1; } public object Current { get {return _per[position]; } } } class Program { static void Main(string[] args) { Person[] per = new Person[2] { new Person("guojing","21"), new Person("muqing","21"), }; Person personlist = new Person(per); foreach (Person p in personlist)//遍历对象 { Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age); } Console.ReadKey(); } } }
2) 实现IEnumerable<T>接口的对象.LINQ方法名(lambda表达式)。
lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 “成为”。
运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体。
lambda表达式:
1.一个参数:param=>expr
2.多个参数:(param-list)=>expr
来看一段代码
namespace lambda { public class Person { public string Name { get; set; } public int Age { get;set; } } class Program { public static List<Person> PersonsList() { List<Person> persons = new List<Person>(); for (int i = 0; i < 7; i++) { Person p = new Person() { Name = i + "儿子", Age = 8 - i, }; persons.Add(p); } return persons; } static void Main(string[] args) {
List<Person> persons = PersonsList();
var person6 = persons.Where(p => p.Age > 6).ToList(); //所有Age>6的Person的集合
System.Console.WriteLine("Age>6);
foreach (Person p in person6)
System.Console.WriteLine("Name is" + p.Name + " Age is" + p.Age);
Person per1 = persons.SingleOrDefault(p => p.Age == 1); //Age=1的单个people类
System.Console.WriteLine("Age=1");
if (per1 == null)
System.Console.WriteLine("不存在");
else
System.Console.WriteLine("Name is" + per1.Name + " Age is" + per1.Age);
Person per2 = persons.SingleOrDefault(p => p.Age == 1); //Age=2的单个people类
System.Console.WriteLine("Age=2");
if (per2 == null)
System.Console.WriteLine("不存在");
else
System.Console.WriteLine("Name is" + per2.Name + " Age is" + per2.Age); System.Console.WriteLine("Contain 儿子");
var personerzi = persons.Where(p => p.Name.Contains("儿子")).ToList(); //所有Name包含儿子的Person的集合
foreach (Person p in personerzi)
System.Console.WriteLine("Name is" + p.Name + " Age is" + p.
}
}
}
好了,了解完这些就可以进入正题了
先看一段代码
namespace ConsoleApplication3 { class IntroToLINQ { static void Main() { // The Three Parts of a LINQ Query: // 1. Data source. int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // 2. Query creation. // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; // 3. Query execution. foreach (int num in numQuery) { Console.Write("{0} ", num); } } } }
在这里LINQ的基本表达方式为
var numQuery = from num in numbers
where (num % 2) == 0
select num;
基本上和sql语句没有什么差别..只是select要放在最后...
而上述代码的运行结果如下