这一节主要向大家讲三个问题,第一个问题什么是LINQ,第二个问题LINQ主要解决什么问题,第三个问题学习LINQ需要做哪些基本的准备。
首先第一个问题,什么是LINQ?LINQ中文翻译为语言集成查询(Language Integrated Query),更通俗的讲,它相当于一个通用的数据查询接口。LINQ最初由Anders hejlsberg构思,2007年11月19日,LINQ作为.NET FrameWork3.5的一部分正式发布,同时微软也将LINQ集成到了Visual Studio 2008中,这一巨大的创新,实现了面向对象和数据访问的互通有无。
第二个问题,LINQ主要解决什么问题?也就是LINQ的设计目的。我们知道在LINQ之前,面向对象和数据访问这两个领域是相互分裂的,编程语言中的数据类型,和数据库中的数据类型也有一些出入,同时SQL和XML都有自己的查询语言而对象却没有自己的查询语言,这些在很大程度上限制开发的效率,而LINQ的设计理念就是在不同类型的数据之间(关系数据、层次模型数据等)之间实现数据访问的互通有无,为不同的数据类型提供统一的访问接口。具体体现为LINQ主要包含了以下三大部分: LINQ to Objects主要负责对象的查询,LINQ to XML 主要负责XML的查询, LINQ to ADO.NET主要负责数据库的查询,而LINQ to ADO.NET又包括 LINQ to SQL,LINQ to DataSet,LINQ to Entrties这三部分。这样就很好的符合了其设计理念,实现了对不同类型的数据访问。
第三个问题,LINQ学习需要做哪些准备?也就是需要掌握哪些前期的基础知识。在开始学习LINQ之前,我们需要先来了解下理解C# 3.0的一些新特性:隐含类型局部变量、自动属性、对象初始化器、集合初始化器、匿名类型、Lambda表达式、扩展方法、局部方法、yield和IEnumerable接口、查询句法。
下面我会通过做一些小例子,把这些特性一一给大家讲解一下。
1、隐含类型的局部变量。
学过Javascript的朋友相信对var这个关键字肯定一点也不陌生,我们都知道Javascript是一种弱类型的语言,所以在运行的时候才会更加的灵活。我们现在所接触的语言大部分都是强类型的语言,所谓强类型的语言,就是程序声明的变量、实例化对象,必须有明确的类型规定,这样在编译的时候就为其分配一定的内存空间,这样的话代码的安全的安全性就比较高,弱类型的语言比较灵活,但是它也比较容易出错也是其诟病之一。为了提高程序的运行效率和灵活性,微软也把var给引进了进来。看下面的例子:
private static void UnknowName()
{
var name = "Olive";
var age = 22;
var address = "北京";
var Frieds = new[] { "Olive", "MoYao", "Momo" };
Console.WriteLine("名字为:"+name);
Console.WriteLine("年龄:" + age * 2);
foreach (var f in Frieds)
{
Console.WriteLine(f);
}
Console.ReadKey();
}
实验结果:
调试时,编译器自动识别数据类型:
运行结果:
由实验结果可知:编译器可以自动识别隐含类型的局部变量,但是前提是变量必须有值,但是在使用null之前,必须要确定类型,例如:var test=(string)null;这样编译器可以自动的推断值类型,如果单纯的为test=null,则编译器无法识别其类型。
2、自动属性
直接看下面代码:
在C#3.0以前创建一个类:
Class Person{
private string name;
private string sex;
private int age;
public string Name
{
get{ return name; }
set{name = value;}
}
public string Sex
{
get { return sex;}
set { sex = value;}
}
public int Age
{
get{ return age;}
set{ age = value;}
}
}
在C#3.0以后可以这样写,相当于一个语法糖,省了很多代码,效果是一样的。
public class Person
{
public string Name
{
get;
set;
}
public string Sex
{
get;
set;
}
public int Age
{
get;
set;
}
}
3、对象初始化器
在这里还是用上边的例子,在C#3.0以前可以这样初始化对象
Person p=new Person();
p.Name="Olive";
p.Sex="女";
p.Age=22;
在C#3.0以后可以这样初始化
Person p=new Person(){ Name="Olive",Sex="女",Age=22};
4、集合初始化器
还是上边的例子:
C#3.0之前
List<Person> list=new List<Person>();
Person p=new Person();
p.Name="Olive";
p.Sex="女";
p.Age=22;
Person p1=new Person();
P1.Name="Moyao";
P1.Sex="男";
P1.Age=23;
list.add(p);
list.add(p1);
C#3.0之后
List<Person> list=new List<Person>()
{
new Person(){ Name="Olive",Sex="女",Age=22},
new Person(){ Name="Moyao",Sex="男",Age=23}
};
5、匿名类型
和隐含类型的局部变量一样,匿名类型就是开发者自定义类型,无须显示定义。在LINQ中匿名类会常常用到。
Var name="Olive";
Var sex="女";
Var age=22;
Var person=new{ Name=name,Sex=sex,Age=age};
Consol.WriteLine("名字:"+person.Name"+"性别:"+person.Sex+"年龄:"+person.Age);
实验结果:
6、Lambda表达式
在讲Lambda表达式之前先讲一下委托,和匿名函数。事实上Lambda表达式是由委托——》匿名函数——》Lambda表达式一步步过渡而来的。
6.1委托:
声明委托: public delegate string ShowLove(string name);
委托调用函数:private static string ShowMyLove(string name)
{
return "I Love you " + name;
}
//在主函数里调用该函数,参数为一个委托对象
private static string Show(ShowLove showLove)
{
string love = showLove("Olive");
return love;
}
结果为:
6.2 在2.0中的匿名函数:
这个时候可以将上边的Show方法写成这样
Private string Show(string name)
{
Delegate(string name)//匿名方法
{
Return "I Love you " +name;
}
}
匿名方法顾名思义就是没有方法名,但是需要用delegate关键字修饰
6.3 Lambda表达式
事实上Lambda表达式和匿名方法差不多,都是用于产生内联方法,但是Lambda表达式的语法更为简洁。语法如下:
(参数列表) =>表达式或者语句块
上边的例子还可以这样写:
Private string Show((name)=>return "I Love you "+ name;);
产生的效果是一样的。
Lambda表达式和匿名函数的区别在于,Lambda的参数可以不写类型,匿名函数的参数类型必须得确定.
只有一个参数时小括号()和大括号{}可以省略不写,
形如:Show(name=>return "I love you "+name");
同时如果执行的代码只有一句话是关键字return、{}也可以省略形如:
Show(name=>"I love you "+name");
如果是需要执行多句话则{}不能省略,形如:
Show(name=>{ string love=name+"116";return love; });
但是如果没有参数时,括号是万不可省略的形如Show(()=>"I Love you");
7、扩展方法
扩展方法多用于对CLR类型进行一些操作的扩展,在3.0之前如果要实现这些操作,一般都是建一下辅助类,扩展方法,能方便的实现这些公共。
在开始做示例之前,先讲些定义扩展方法需要注意的地方:
1、扩展方法只能在静态类中定义并且是静态方法,
2、扩展方法不能与原有方法名冲突,否则将无效
3、扩展方法的参数必须为(this扩展类 类实例,Parameter p)
请看示例:比如要对string类进行扩展
//String 的扩展类
public static class ExtensionString
{
public static string ShowLove(this string s)
{
return "I Love " + s;
}
}
调用:Console.WriteLine("Olive".ShowLove());
结果:
8、局部方法
谈到局部方法,首先要说一下局部类,局部类是用Partial修饰的类,可以由多个partial修饰的同名类组合成一个类,局部方法是3.0以后加入的特性,局部方法必须定义在局部类中,但是局部方法的定义和实现可以分开。在这里同时也需要注意,局部的方法的返回值必须是静态的返回值必须是void,可以有参也可以无参,有无方法实现均可。
下边来看示例:
public partial class PartialTest
{
partial void Show(string name);
}
public partial class PartialTest
{
partial void Show(string name)
{
Console.WriteLine("名字:" + name);
}
}
在主函数中调用
PartialTest p=new PartialTest();
//p.Show();//这个时候你会发现对象p里根本没有Show()方法,因为默认的Partial方法为私有方法,可能有人会想有private修饰一下,这个时候也不能这样做,只需要它是私有的就可以了
那么该如何调用局部方法呢?
我们可以在对象的构造函数里进行调用:
以上的代码做如下修改
public partial class PartialTest
{
PatrialTest( string name)
{
Show(sname);
}
partial void Show(string name)
{
Console.WriteLine("名字:" + name);
}
}
结果:
在这里需要注意的是局部函数是私有类型的,但是不能用Private来修饰,如果需要调用的话,可以在构造函数里进行调用。
9、yield关键字
我们知道如果想要能够foreach遍历的话,必须要实现IEnumerable接口,GetEnumerator()方法,而yield关键字是用来帮助IEnumerable对象自动生成一个辅助IEnumerator对象。但是yield关键字只能用在retur关键字或break关键字之前。
请看示例:(该示例引自Rookie_J博客)
(1)定义一个实现了接口IEnumerable的类MyYield:
class MyYield : IEnumerable
{
publicint StartCountdown;
public IEnumerator GetEnumerator()
{
for (int i= StartCountdown; i>=0; i--)
yieldreturn i;//yield自动生成一个实现了接口IEnumerator的类
}
}
(2)建立Myield类的对象,且通过foreach实现列举功能:
MyYield myYield=new MyYield() { StartCountdown=10};
foreach (int nin myYield)
{
Console.WriteLine(n);
}
10、查询语法。
学到这里,你基本上已经把学习LINQ的前期铺垫给做好了,下面就来接触下我们要学习的LINQ查询语法吧。在这里只是做一个简单的介绍,让大家对此有个大致的了解,下一节我会具体的介绍LINQ的查询语法。
还是以上边创建的Person类为例:
List<Person> list = new List<Person>() { new Person() { Name = "Olive", Age = 22, Sex = "女" }, new Person() { Name = "Moyao", Age = 22, Sex = "男" } };
Var linqperson=from p in list where p.Name="Moyao" select p;
Foreach(Person p in linqperson)
{
Console.WriteLine(p.Name+"-----"+p.Age+"---p.Sex);
}
结果如下:
先做一个大概的解析LINQ语法形式:from in where select
SQL语法形式:select from where
是不是很像呢?
好吧,下一节我会慢慢给大家分享。