Linq lambda 匿名方法

课程6  委托、匿名方法、Lambda表达式、Linq查询表达式
上课日志1
一、委托的基本认识
提问:能不能把方法作为参数传递???
也即是能不能声明一个能存放方法的变量呢——委托。
委托是一种数据类型,像类一样(可以声明委托类型变量),委托是用来接受方法的,通过委托可以把方法作为参数进行传递。
namespace _01委托的基本认识
{
//1.定义委托类型。定义一个委托类型(委托是一种数据类型,能接受方法的数据类型),用来保存无参数,无返回值的方法
//委托最好要定义在命名空间中,和类是同一个级别
public delegate void MyDelegate();//也像定义抽象方法一样,没有实现(方法体)
// public class MyClass { } //这是定义一个类 class Program
{
//void Run();//定义抽象方法
//string Test();//定义抽象方法
static void Main(string[] args)
{
//2.使用委托第二步:声明委托变量,并赋值
//声明了一个委托变量md,并且new了一个委托对象,并且把方法M1传递了进去
//即md委托保存了M1方法 //MyClass mc=new MyClass();
//MyDelegate md = new MyDelegate(M1);//第1种写法
MyDelegate md = M1;////第2种写法 //3.调用md委托的时候就相当于调用M1方法
md();//与下面那就等同
//md.Invoke();//Invoke()的作用是执行指定的委托
Console.WriteLine("ok");
Console.ReadKey();
}
static void M1()
{
Console.WriteLine("我是一个没有参数没有返回值的方法");
}
}
}
二、委托的基本应用举例1
需求:假设一件事情在前面和后面要做的事情比较固定(这里假设输出“========”),但是中间要做的事情经常发生变化(比如1.要输出系统当前时间到控制台,.要输出系统当前是星期几,.要把系统时间写入到文本文件等)
namespace _02委托的基本应用
{
//定义一个委托
public delegate void middleDelegate(); public class TestClass
{
public void DoSomething(middleDelegate middleThing)//委托类型作为参数,也即是调用此方法要传递一个方法进来
{
Console.WriteLine("==========================");
Console.WriteLine("==========================");
//执行完第二句代码,输出下系统时间
//Console.WriteLine(System.DateTime.Now.ToString());
if (middleThing != null)//委托是一个对象,就有可能为null,所以先判断下是否为null
{
middleThing ();
}
Console.WriteLine("==========================");
Console.WriteLine("==========================");
}
}
}
namespace DelegateApp1
{
class Program
{
static void Main(string[] args)
{
TestClass tc = new TestClass();
tc.DoSomething(PrintTimeToConsole);
Console.ReadKey();
}
public static void PrintTimeToConsole()
{
Console.WriteLine(System.DateTime.Now.ToString());
}
static void writeTimeToFile()
{
File.WriteAllText("time.txt", System.DateTime.Now.ToString());
}
public static void PrintWeekToConsole()
{
Console.WriteLine(System.DateTime.Now.DayOfWeek.ToString());
}
}
}
三、委托的基本应用举例2与总结
从上例可以看出委托一般是在一个方法()的一大段程序中间“挖个坑”,这个坑用来执行另一个方法(),而这个方法()是动态的,可以根据需要调用不同的方法到方法()中。
需求:对字符串的处理经常要发生变化,比如在字符串两端加“=”、加“★”,把字符串字母全部转换为大写。
namespace _03委托的基本应用练习与总结
{
//定义一个委托(委托是一种数据类型,接受方法的数据类型)
public delegate string GetStringDelegate(string str); public class TestClass
{
public void ChangeStrings(string[] strs, GetStringDelegate GetString)
{
for (int i = ; i < strs.Length; i++)
{
strs[i] = GetString(strs[i]);//由于对字符串的需求有很多种,所以把对字符串变化部分用委托封装成一个方法
}
}
}
} static void Main(string[] args)
{
TestClass tc = new TestClass();
string[] names = new string[] { "ZhangSan", "LiSi", "WangWu", "LaoLiu" };
/*下面就可以调用含有委托的方法,如果需要在字符串两端加★,就调用ChangesStrings2方法
/如果需要把字符串的字母转换为大写,就调用ChangesStrings3方法,这样就灵活了*/
//tc.ChangeStrings(names, ChangesStrings1);//应用需求1
//tc.ChangeStrings(names, ChangesStrings2);//应用需求2
tc.ChangeStrings(names, ChangesStrings3);//应用需求3
//把变化后的字符串数组中的字符串输出
for (int i = ; i < names.Length; i++)
{
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
static string ChangesStrings3(string str)//需求3:把字符串中字母转换为大写
{
return str.ToUpper();
}
static string ChangesStrings2(string strs)//需求2:在字符串两端加★
{
return "★" + strs + "★";
}
static string ChangesStrings1(string strs)//需求1:在字符串两端加★
{
return "=" + strs + "=";
}
委托认识的总结:
委托是一种数据类型,像类一样的一种数据类型。一般都是直接在命名空间中定义。
定义委托时,需要指明返回值类型、委托名与参数列表,这样就能确定该类型的委托能存储(接受)什么样的方法。
使用委托
()声明委托变量
()委托是一个引用类型,就像类一样,所以当声明委托变量后,如果不赋值则该委托变量为null。所以在使用委托变量前最好做非空校验if(weituo!=null) 四、泛型委托Action与Action<T>
、Action委托(非泛型版本)
例1 :
public delegate void Mydelegate();
class Program
{
static void Main(string[] args)
{
Mydelegate md = new Mydelegate(M1);
md();
//系统内置了三种委托,像这种委托就可以用系统内置委托Action,完全不用自已写。Action委托就是一个无参数无返回值的委托(非泛型版本)
Action action = M1;
action();
Console.ReadKey();
}
static void M1()
{
Console.WriteLine("ok");
}
}
、自己写泛型委托
例2:如果自己写非泛型委托:需要保存一个string类型参数,但无返回值的方法,就需要写一个委托
需要保存一个int类型参数,但无返回值的方法,就需要再写一个委托
需要保存一个bool类型参数,但无返回值的方法,就需要再另外写一个委托等等,这样的话就得写很多委托,
于是我们就可以写泛型委托,一次性搞定。
public delegate void Mydelegate1(string msg);
public delegate void Mydelegate2(int msg);
public delegate void Mydelegate3(bool msg); public delegate void MyGenericdelegate<T>(T args);//这个委托就可以接受1个参数,无返回值的方法,但是这个参数数据类型可以任意
class Program
{
static void Main(string[] args)
{
MyGenericdelegate<string> md1 = M1;
md1("一个参数");
MyGenericdelegate<int> md2 = M1;
md2();
MyGenericdelegate<bool> md3 = M1;
md3(true);
Console.ReadKey();
}
static void M1(string msg)
{
Console.WriteLine(msg);
}
static void M1(int msg)
{
Console.WriteLine(msg);
}
static void M1(bool b)
{
Console.WriteLine(b);
}
} 这种情况就可以直接使用系统提供的泛型委托Action<T>。
、Action<T>委托(泛型版本)
Action<T>委托的泛型版本是一个无返回值,但是参数个数及类型可以改变的委托。
例子3:
class Program
{
static void Main(string[] args)
{
Action<string> action1 = M1;
action1("内置无返回值的泛型委托");
Action<int> action2 = M1;
action2();
Action<bool> action3=M1;
action3(true);
Console.ReadKey();
}
static void M1(string msg)
{
Console.WriteLine(msg);
}
static void M1(int msg)
{
Console.WriteLine(msg);
}
static void M1(bool b)
{
Console.WriteLine(b);
}
} 系统提供了三种委托,所以以后一般不需要自己去定义委托,直接用系统内部提供的就可以
Action——Action委托的非泛型版本就是一个无参数无返回值的委托
Action<T>——Action<T>委托的泛型版本是一个无返回值,但是参数个数及类型可以改变的委托
Func<T>——Func委托只有泛型版本的,接受参数个数可以是若干个,也可以是没有参数,但是一定有返回值的方法(下节讲)

课程6  委托、匿名方法、Lambda表达式、LINQ查询表达式

上课日志2

补充—VS中自定义C#快速简写代码(输入简写字母后按两次Tab键自动输入

在VS中选择工具——>代码段管理器(语言下拉框选择Visual C#,如下图1所示),位置下面的下拉列表框再选择Visual C#,然后复制位置文本框里的路径,即找到代码段简写文件(*.snippet)。

然后随便复制一个(比如cw.snippet),复制的位置可以任意(注意两点:第一、不要在原来的cw.snippet位置,第二、需要新建一个文件夹(zdy)来存储复制过来的cw.snippet文件)

然后再对复制过来的文件修改(比如需要创建快速输入Console.ReadKey(),可以把文件名改为crk.snippet),接着打开重命名后的文件(crk.snippet)修改里面的内容(如图2所示),参照图3进行修改(修改绿色框住的4个地方即可)

最后单击图1下面的添加按钮,选择到自定义的文件夹(zdy)。

Linq lambda 匿名方法

图1

Linq lambda 匿名方法

图2

Linq lambda 匿名方法Linq lambda 匿名方法Linq lambda 匿名方法Linq lambda 匿名方法Linq lambda 匿名方法

图3

二、泛型委托Func<T>

Fun<T>——Func委托只有泛型版本的,接受参数个数可以是若干个,也可以是没有参数,但是一定有返回值的方法。

Func<TResult>这个表示没有参数,只有返回值的

Func<T,TResult>这个表示有1个参数,有返回值的

Func<T1,T2,TResult>这个表示有2个参数(前两个参数T1,T2表示参数,最后TResult返回值),有返回值的

Func<T1,T2,T3,TResult>这个表示有3个参数(前三个参数T1,T2,T3,表示参数,最后TResult返回值),有返回值的.

总之Func委托最后一个TResult表示返回值,前面的不管多少个T都是表示参数

例:

class Program

{

static void Main(string[] args)

{

#region 无参数有返回值的Fun委托

Func<int> fun1 = M1;

int n1 = fun1();

Console.WriteLine(n1);

#endregion

#region 有参数有返回值的Fun委托

Func<int, int, int, int> fun2 = M2;

int n2 = fun2(1, 2, 3);

Console.WriteLine(n2);

#endregion

Console.ReadKey();

}

static int M1()

{

return 1;

}

static int M2(int n1, int n2, int n3)

{

return n1 + n2 + n3;

}

}

三、多播委托

多播委托就是一个委托同时绑定多个方法,多播委托也叫委托链、委托组合。

1、绑定无返回值的多个委托

class Program

{

static void Main(string[] args)

{

#region 绑定无返回值的多个委托

Action<string> action = M1;//这句话只绑定一个M1方法(绑定第一个方法不能用+=复制,因为开始action为null,所以只能用=赋值),下面再给acion绑定方法

action += M2;

action += M3;

action += M4;

action += M5;

action -= M3;//解除绑定M3方法(即是用-=赋值为解除绑定方法)

action("多播委托");

#endregion

Console.ReadKey();

}

static void M1(string msg)

{

Console.WriteLine(msg);

}

static void M2(string msg)

{

Console.WriteLine(msg);

}

static void M3(string msg)

{

Console.WriteLine(msg);

}

static void M4(string msg)

{

Console.WriteLine(msg);

}

static void M5(string msg)

{

Console.WriteLine(msg);

}

}

2、绑定返回值的多个委托如何获取到每个方法的返回值

class Program

{

static void Main(string[] args)

{

#region 绑定有返回值的多个委托

Func<string, string> fc = T1;

fc += T2;

fc += T3;

string result= fc("有参数有返回值的多播委托");

Delegate[] delegates = fc.GetInvocationList();//按照调用顺序返回此多播委托的调用列表。即是有几个方法就有个几个委托,返回值为Delegate数组

for (int i = 0; i < delegates.Length; i++)//循环遍历Delegate数组即可得到每个委托对象.这样就可以逐个委托调用,如果有返回值,可以逐个拿到

{

//delegates[i](“……”);这句不行,因为Delegate是抽象类,所以不能直接调用,需要强转为子类                //(delegates[i] as Func<string,string>)();//没有返回值就这样就可以,如果有返回值类似下一行代码就可以

string s = (delegates[i] as Func<string, string>)("获取多播委托每个方法的返回值");

Console.WriteLine(s);

}

#endregion

Console.ReadKey();

}

static string T1(string msg)

{

return msg+"1";

}

static string T2(string msg)

{

return msg + "2";

}

static string T3(string msg)

{

return msg + "3";

}

}

四、匿名方法

1、匿名类

static void Main(string[] args)

{

#region 匿名类

var Anon = new { Name = "小明", Age = 3, Sex = '男' };

Console.WriteLine("我的名字是:{0},性别为{1},年龄是{2}", Anon.Name, Anon.Sex, Anon.Age);

Console.ReadKey();

#endregion

}

2、匿名方法

匿名方法,即是没有名字的方法,不能直接在类中定义,而是在给委托变量赋值的时候,需要赋值一个方法,此时可以“现做现卖”,定义一个匿名方法传递给该委托。

匿名方法关键字delegate,delegate后的括号写方法参数,{ }里面写方法体,这是一个赋值语句所以最后需要分号。

例1:

#region 匿名方法(无参数无返回值)

//如果存在一个已定义好的M1方法,则直接可以把该方法赋给委托变量md

// Action md = M1;

//如果不存在已定义好的方法,则可以使用匿名方法赋给委托变量,即现定义一个方法给委托变量

Action  md = delegate()

{

Console.WriteLine("ok");

};

md();//调用匿名方法

Console.ReadKey();

#endregion

static void M1()

{

Console.WriteLine("ok");

}

例2:

#region 有参数无返回值的匿名方法

Action<string> md2 = delegate(string msg)

{

Console.WriteLine("Hello!" + msg);

};

md2("大家好!");

Console.ReadKey();

#endregion

例3:

#region 有参数有返回值的匿名方法

Func<int,int,int,int> ad = delegate(int n1, int n2, int n3)//提问:这里如果不采用匿名方法怎么写

{

return n1 + n2 + n3;

};

int result = ad(12, 10, 8);

Console.WriteLine(result);

Console.ReadKey();

#endregion

五、Lambda表达式

1、Lambda介绍

“Lambda 表达式”(lambda expression)就是一个匿名函数(匿名方法),Lambda表达式基于数学中的λ演算得名。

Lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他:“转到”或者 “成为”,读作 “goes to”。运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体(方法体)。

lambda表达式:

一个参数:param=>expr

多个参数:(param-list)=>expr

2、输入参数与表达式或语句块

输入参数:在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0、1或者多个。只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略。输入参数的数量大于或者等于2时,Lambda表达式左边的一对小括弧中的多个参数之间使用逗号(,)分割。

表达式或语句块:多个Lambda表达式可以构成Lambda语句块。语句块是放到运算符的右边,作为Lambda的主体。语句块中可以包含多条语句,并且可以包含循环、方法调用和if语句等。语句块必须被"{"和"}"包围。

例1:无参数、表达式

#region 无参数

//Action a = () => { Console.WriteLine("This is a Lambda expression."); };

Action a= ()=>Console.WriteLine("This is a Lambda expression.");

a();

Console.ReadKey();

#endregion

由于上述Lambda表达式的输入参数的数量为0,因此,该Lambda表达式的左边部分的一对小括弧不能被省略。右边是一个表达式

例2:1个参数情况、语句块

#region 1个参数

Action<int> b = m => { int n = m * 2; Console.WriteLine(n); };//此处参数m的括号可以省略

b(2);

#endregion

上述Lambda表达式的输入参数省略了一对小括弧,它与“(m)=> { int n = m * 2; Console.WriteLine(n); };是等效的。右边是语句块,那么该语句块必须被"{"和"}"包围,还有return语句不能省略花括号。

例3:多个参数、语句块

#region 多个参数

Action<int,int> c = (m,n) => { int s = m * n; Console.WriteLine(s); };//此处参数的括号不能省略

c(2,3);

#endregion

六、匿名方法、Lambda表达式应用巩固举例

1、匿名方法与Lambda的替

static void Main(string[] args)

{

//Func<int, int, int, int> ad = M2;

#region 有参数有返回值的匿名方法

Func<int, int, int, int> ad = delegate(int n1, int n2, int n3)//该匿名方法实际上与下面的有名方法M2一样

{

return n1 + n2 + n3;

};

int result = ad(12, 10, 8);

Console.WriteLine(result);

#endregion

#region 有参数有返回值的lambda表达式

Func<int, int, int, int> ad2 = (x, y, z) => { return x + y + z; };

int r = ad2(10, 20, 30);

Console.WriteLine(r);

#endregion

Console.ReadKey();

}

static int M2(int n1, int n2, int n3)

{

return n1 + n2 + n3;

}

说明:匿名方法、lambda表达式运行时最终都会编译成方法

2定义一个能接收参数个数可变有返回值的委托

public delegate int Adddelegate(params int[] arr);//定义一个能接收参数个数可变且有返回值的委托

static void Main(string[] args)

{

#region 接收参数个数可变的lambda表达式

Adddelegate ad = (arr) =>

{

for (int i = 0; i < arr.Length; i++)

{

Console.WriteLine(arr[i]);

}

return arr.Sum();

};

int x = ad(1, 2, 3, 4, 5);

Console.WriteLine(x);

Console.ReadKey();

#endregion

}

3lambda表达式在泛型集合中的应用

示例:打印出泛型集合中大于6的元素。

static void Main(string[] args)

{

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 89, 10, 11, 12, 13, 14, 15 };

//第一种写法自己定义方法

IEnumerable<int> ie = list.Where(cs); //var

//第二种写法用匿名方法

//IEnumerable<int> ie = list.Where(delegate(int n)

//{

//    return n > 6;

//}

//    );//where里面需要一个方法作为参数(有1个int类型参数,返回值为bool类型)

//第三种写法使用lambda表达式

//IEnumerable<int> ie = list.Where(n => { return n > 6; });

foreach (var item in ie)

{

Console.WriteLine(item);

}

Console.ReadKey();

#endregion

}

static bool cs(int n)

{

return n > 6;

}

七、Linq简介

LINQ的全称是Language Integrated Query,中文译成“语言集成查询”。LINQ是一种查询技术,有LINQ to SQL、LINQ to Object、LINQ to ADO.NET、LINQ to XML、LINQ to EF等。

LINQ与直接SQL语句比较:

(1)SQL数据库技术是一门相对比较复杂深奥的技术,不是人人都懂,而LINQ To SQL比较简单(实际上底层都对数据库操作进行了封装,架构了数据访问层)

(2)直接写SQL语句,如果有问题,只有到运行时才知道

(3)LINQ To SQL可以很好的防止注入式攻击

(4)Linq是面向对象的查询,主要在程序内部使用(比如查找所需的数据),比使用DataReader读取数据等方便多了;直接SQL是面向关系型数据库的查询

(5)从运行效率上来说性能不如直接SQL语句,但是开发效率提高了。

要学习LINQ首先就要学习LINQ查询表达式。

LINQ的查询由3基本部分组成:获取数据源,创建查询,执行查询。

// 1.获取数据源

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

// 2.创建查询

var numQuery = from num in numbers

where num % 2 == 0

select num*10;

//与SQL语句比较下

//string ql=”select StuName from Student where ID>1”

// 3.执行查询

foreach (var num in numQuery)

{

Console.WriteLine(num);

}

在 LINQ 中,查询的执行与查询本身截然不同;换句话说,如果只是创建查询变量,则不会检索任何数据。

Linq的数据源要求必须实现IEnumerable或IEnumerable<T>接口,数组隐式支持这个接口。numQuery叫做查询变量,它存储了一个查询表达式。注意,声明查询变量并不会执行查询,真正的执行查询延迟到了foreach语句中。

查询表达式必须以from子句开头,以select或group子句结束。第一个from子句和最后一个select子句或group子句之间,可以包含一个或多个where子句、let子句、join子   句、orderby子句和group子句,甚至还可以是from子句。它包括8个基本子句,具体说明如下所示。

●from子句:指定查询操作的数据源和范围变量。

●select子句:指定查询结果的类型和表现形式。

●where子句:指定筛选元素的逻辑条件。

●let子句:引入用来临时保存查询表达式中的子表达式结果的范围变量。

●orderby子句:对查询结果进行排序操作,包括升序和降序。

●group子句:对查询结果进行分组。

●into子句:提供一个临时标识符。join子句、group子句或select子句可以通过该标识符引用查询操作中的结果。

●join子句:连接多个用于查询操作的数据源。

八、Form子句

创建一个LINQ表达式必须要以from子句开头。

例1:单个Form子句

string[] values = { "中国", "日本", "美国", "菲律宾", "越南" };

//查询包含“国”的字符串

// IndexOf查询参数字符串在父串中首次出现的位置,没有返回-1

var valueQuery = from v in values

where v.IndexOf("国") > 0

select v;

foreach (var v in valueQuery)

{

Console.WriteLine(v);

}

Console.ReadKey();

在这个LINQ表达式的from子句中,v叫做范围变量,values是数据源。v的作用域存在于当前的LINQ表达式,表达式以外不能访问这个变量。where用来筛选元素,select用于输出元素。这里的范围变量v和foreach语句中的隐式变量v都可以由编译器推断出其类型。

例2:复合Form子句

在查询数据源中,元素的属性是一个集合时,可以使用复合from子句对这个属性集合查询。比如,一个客户,可能有多个电话。

class CustomerInfo

{

public string Name { get; set; }

public int Age { get; set; }

public List<string> TelTable { get; set; }

}

static void Main(string[] args)

{

formExpDemo();

Console.ReadKey();

}

static void formExpDemo()

{

List<CustomerInfo> customers = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, TelTable=new List<string>{"1330708****","1330709****"}},

new CustomerInfo{ Name="上官飘飘", Age=17, TelTable=new List<string>{"1592842****","1592843****"}},

new CustomerInfo{ Name="诸葛菲菲", Age=23, TelTable=new List<string>{"1380524****","1380525****"}}

};

//查询包含电话号码1592842****的客户

var query = from CustomerInfo ci in customers//ci

from tel in ci.TelTable

where tel.IndexOf("1592842****") > -1

select ci;

foreach (var ci in query)

{

Console.WriteLine("姓名:{0} 年龄:{1}", ci.Name, ci.Age);

foreach (var tel in ci.TelTable)

{

Console.WriteLine("          电话:{0}", tel);

}

}

}

九、where子句select子句

1where子句

where子句的作用就是筛选元素,除了开始和结束位置,where子句几乎可以出现在LINQ表达式的任意位置。一个LINQ表达式中可以有where子句,也可以没有;可以有一个,可以有多个;多个where子句之间的关系相当于逻辑“与”,每个where子句可以包含1个或多个逻辑表达式,这些条件成为“谓词”,多个谓词之间用布尔运算符隔开,比如逻辑“与”用&&,逻辑“或”用||,而不是用SQL中的AND或OR。

class CustomerInfo

{

public string Name { get; set; }

public int Age { get; set; }

public string Tel { get; set; }

}

List<CustomerInfo> clist = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},

new CustomerInfo{ Name="令狐冲", Age=23, Tel ="1380524****"}

};

//查询名字是3个字或者姓“令”的,但年龄大于20的客户

var query = from customer in clist

where (customer.Name.Length == 3 || customer.Name.Substring(0, 1) == "令") && customer.Age > 20

select customer;

foreach (var ci in query)

{

Console.WriteLine("姓名:{0} 年龄:{1} 电话:{2}", ci.Name, ci.Age, ci.Tel);

}

2select子句

例1:最简单的select就是直接输出from子句建立的那个范围变量:

#region 简单的select示例

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

var query = from n in arr

select n;  //select n*10;对象.属性

#endregion

例2:对查询结果进行投影(转换)。下面查询表达式查询arr数组中的每一个元素,查询结果转换为一个集合对象的两个属性值:ID和Name,它在select子句中由匿名对象初始化器创建。每一个对象的ID属性的值是当前元素的值、Name属性的值为元素的值的字符串的表现形式。

#region 对查询结果进行投影(转换)

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

var query = from n in arr

select new

{

ID = n,

Name = n.ToString()

};

foreach (var item in query)

{

Console.WriteLine(item.ID+"  张"+item.Name);

}

Console.ReadKey();

#endregion

十、Group子句into子句及orderby子句

1Group子句

LINQ表达式必须以from子句开头,以select或group子句结束,所以除了使用select子句外,也可以使用guoup子句来返回元素分组后的结果。group子句用来将查询结果分组,并返回一对象序列。这些对象包含零个或更多个与该组的key值匹配的项。

注意:每一个分组都不是单个元素,而是一个序列(也属于集合)。序列的元素类型为IGrouping<TKey,TElement>(必须以Group子句结束的LINQ表达式,分组结果类型才为序列,序列的元素类型为IGrouping<TKey,TElement>)

List<CustomerInfo> clist = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},

new CustomerInfo{ Name="欧阳锦鹏", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官无忌", Age=23, Tel ="1380524****"}

};

//按照名字的前2个字进行分组

var query = from customer in clist

group customer by customer.Name.Substring(0, 2);

//foreach (IGrouping<string, CustomerInfo> group in query)

foreach (var group in query)

{

Console.WriteLine("分组键:{0}", group.Key);

foreach (var ci in group)

{

Console.WriteLine("姓名:{0} 电话:{1}", ci.Name, ci.Tel);

}

Console.WriteLine("***************************************");

}

2into子句

into子句可以用来创建一个临时标识符,将group、join或select子句的结果存储到这个标识符中。

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

var query = from n in arr

where n > 1 && n < 6

group n by n % 2 into g

from sn in g

select sn;

foreach (var item in query)

{

Console.WriteLine(item);

}

3orderby子句(中间无空格

orderby子句可使返回的查询结果按升序或者降序排序。升序由关键字ascending指定,而降序由关键字descending指定。

注意:orderby子句默认排序方式为升序。

示例1:

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

var query = from n in arr

where n > 1 && n < 6

orderby n descending

select n;

示例2:

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

var query = from n in arr

where n > 1 && n < 6

orderby n % 2 ascending, n descending

select n;

n%2:按照升序排序;n:按照降序排序。

注意:n%2排序关键字优先级大于n排序关键字。因此,该查询表达式的结果首先按照n%2排序关键字升序排序,然后再按照n排序关键字降序排序。第一个排序关键字后的"ascending"可以省略。因为默认排序方式为升序。

十一、let子句join子句

1let子句

let子句用于在LINQ表达式中存储子表达式的计算结果。即let子句创建一个范围变量来存储结果,变量被创建后,不能修改或把其他表达式的结果重新赋值给它。此范围变量可以在后续的LINQ子句中使用。

List<CustomerInfo> clist = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},

new CustomerInfo{ Name="郭靖", Age=17, Tel ="1330708****"},

new CustomerInfo{ Name="黄蓉", Age=17, Tel ="1300524****"}

};

//姓“郭”或“黄”的客户

var query = from customer in clist

let g = customer.Name.Substring(0, 1)

where g == "郭" || g == "黄"

select customer;

foreach (var ci in query)

{

Console.WriteLine("姓名:{0} 年龄:{1} 电话:{2}", ci.Name, ci.Age, ci.Tel);

}

 

//where customer.Name.Substring(0, 1) == "郭" || customer.Name.Substring(0, 1) == "黄"

2join子句

join子句用来连接两个数据源,即设置两个数据源之间的关系。join子句支持以下3种常见联接方式。

内部联接:要求两个数据源都必须存在相同的值,即两个数据源都必须存在满足联接关系的元素。类似于SQL语句中的inner join子句。

分组联接:包含into子句的join子句。

左外部联接:元素的链接关系必须满足联接中的左数据源,类似于SQL语句中的left join子句。

内部连接示例:

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

int[] arrb = new int[] { 0, 2, 4, 6, 8 };

var query = from a in arra

where a < 7

join b in arrb on a equals b

select a;

课程6  委托、匿名方法、Lambda表达式、LINQ查询表达式

上课日志2

补充—VS中自定义C#快速简写代码(输入简写字母后按两次Tab键自动输入

在VS中选择工具——>代码段管理器(语言下拉框选择Visual C#,如下图1所示),位置下面的下拉列表框再选择Visual C#,然后复制位置文本框里的路径,即找到代码段简写文件(*.snippet)。

然后随便复制一个(比如cw.snippet),复制的位置可以任意(注意两点:第一、不要在原来的cw.snippet位置,第二、需要新建一个文件夹(zdy)来存储复制过来的cw.snippet文件)

然后再对复制过来的文件修改(比如需要创建快速输入Console.ReadKey(),可以把文件名改为crk.snippet),接着打开重命名后的文件(crk.snippet)修改里面的内容(如图2所示),参照图3进行修改(修改绿色框住的4个地方即可)

最后单击图1下面的添加按钮,选择到自定义的文件夹(zdy)。

Linq lambda 匿名方法

图1

Linq lambda 匿名方法

图2

Linq lambda 匿名方法Linq lambda 匿名方法Linq lambda 匿名方法Linq lambda 匿名方法Linq lambda 匿名方法

图3

二、泛型委托Func<T>

Fun<T>——Func委托只有泛型版本的,接受参数个数可以是若干个,也可以是没有参数,但是一定有返回值的方法。

Func<TResult>这个表示没有参数,只有返回值的

Func<T,TResult>这个表示有1个参数,有返回值的

Func<T1,T2,TResult>这个表示有2个参数(前两个参数T1,T2表示参数,最后TResult返回值),有返回值的

Func<T1,T2,T3,TResult>这个表示有3个参数(前三个参数T1,T2,T3,表示参数,最后TResult返回值),有返回值的.

总之Func委托最后一个TResult表示返回值,前面的不管多少个T都是表示参数

例:

class Program

{

static void Main(string[] args)

{

#region 无参数有返回值的Fun委托

Func<int> fun1 = M1;

int n1 = fun1();

Console.WriteLine(n1);

#endregion

#region 有参数有返回值的Fun委托

Func<int, int, int, int> fun2 = M2;

int n2 = fun2(1, 2, 3);

Console.WriteLine(n2);

#endregion

Console.ReadKey();

}

static int M1()

{

return 1;

}

static int M2(int n1, int n2, int n3)

{

return n1 + n2 + n3;

}

}

三、多播委托

多播委托就是一个委托同时绑定多个方法,多播委托也叫委托链、委托组合。

1、绑定无返回值的多个委托

class Program

{

static void Main(string[] args)

{

#region 绑定无返回值的多个委托

Action<string> action = M1;//这句话只绑定一个M1方法(绑定第一个方法不能用+=复制,因为开始action为null,所以只能用=赋值),下面再给acion绑定方法

action += M2;

action += M3;

action += M4;

action += M5;

action -= M3;//解除绑定M3方法(即是用-=赋值为解除绑定方法)

action("多播委托");

#endregion

Console.ReadKey();

}

static void M1(string msg)

{

Console.WriteLine(msg);

}

static void M2(string msg)

{

Console.WriteLine(msg);

}

static void M3(string msg)

{

Console.WriteLine(msg);

}

static void M4(string msg)

{

Console.WriteLine(msg);

}

static void M5(string msg)

{

Console.WriteLine(msg);

}

}

2、绑定返回值的多个委托如何获取到每个方法的返回值

class Program

{

static void Main(string[] args)

{

#region 绑定有返回值的多个委托

Func<string, string> fc = T1;

fc += T2;

fc += T3;

string result= fc("有参数有返回值的多播委托");

Delegate[] delegates = fc.GetInvocationList();//按照调用顺序返回此多播委托的调用列表。即是有几个方法就有个几个委托,返回值为Delegate数组

for (int i = 0; i < delegates.Length; i++)//循环遍历Delegate数组即可得到每个委托对象.这样就可以逐个委托调用,如果有返回值,可以逐个拿到

{

//delegates[i](“……”);这句不行,因为Delegate是抽象类,所以不能直接调用,需要强转为子类                //(delegates[i] as Func<string,string>)();//没有返回值就这样就可以,如果有返回值类似下一行代码就可以

string s = (delegates[i] as Func<string, string>)("获取多播委托每个方法的返回值");

Console.WriteLine(s);

}

#endregion

Console.ReadKey();

}

static string T1(string msg)

{

return msg+"1";

}

static string T2(string msg)

{

return msg + "2";

}

static string T3(string msg)

{

return msg + "3";

}

}

四、匿名方法

1、匿名类

static void Main(string[] args)

{

#region 匿名类

var Anon = new { Name = "小明", Age = 3, Sex = '男' };

Console.WriteLine("我的名字是:{0},性别为{1},年龄是{2}", Anon.Name, Anon.Sex, Anon.Age);

Console.ReadKey();

#endregion

}

2、匿名方法

匿名方法,即是没有名字的方法,不能直接在类中定义,而是在给委托变量赋值的时候,需要赋值一个方法,此时可以“现做现卖”,定义一个匿名方法传递给该委托。

匿名方法关键字delegate,delegate后的括号写方法参数,{ }里面写方法体,这是一个赋值语句所以最后需要分号。

例1:

#region 匿名方法(无参数无返回值)

//如果存在一个已定义好的M1方法,则直接可以把该方法赋给委托变量md

// Action md = M1;

//如果不存在已定义好的方法,则可以使用匿名方法赋给委托变量,即现定义一个方法给委托变量

Action  md = delegate()

{

Console.WriteLine("ok");

};

md();//调用匿名方法

Console.ReadKey();

#endregion

static void M1()

{

Console.WriteLine("ok");

}

例2:

#region 有参数无返回值的匿名方法

Action<string> md2 = delegate(string msg)

{

Console.WriteLine("Hello!" + msg);

};

md2("大家好!");

Console.ReadKey();

#endregion

例3:

#region 有参数有返回值的匿名方法

Func<int,int,int,int> ad = delegate(int n1, int n2, int n3)//提问:这里如果不采用匿名方法怎么写

{

return n1 + n2 + n3;

};

int result = ad(12, 10, 8);

Console.WriteLine(result);

Console.ReadKey();

#endregion

五、Lambda表达式

1、Lambda介绍

“Lambda 表达式”(lambda expression)就是一个匿名函数(匿名方法),Lambda表达式基于数学中的λ演算得名。

Lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他:“转到”或者 “成为”,读作 “goes to”。运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体(方法体)。

lambda表达式:

一个参数:param=>expr

多个参数:(param-list)=>expr

2、输入参数与表达式或语句块

输入参数:在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0、1或者多个。只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略。输入参数的数量大于或者等于2时,Lambda表达式左边的一对小括弧中的多个参数之间使用逗号(,)分割。

表达式或语句块:多个Lambda表达式可以构成Lambda语句块。语句块是放到运算符的右边,作为Lambda的主体。语句块中可以包含多条语句,并且可以包含循环、方法调用和if语句等。语句块必须被"{"和"}"包围。

例1:无参数、表达式

#region 无参数

//Action a = () => { Console.WriteLine("This is a Lambda expression."); };

Action a= ()=>Console.WriteLine("This is a Lambda expression.");

a();

Console.ReadKey();

#endregion

由于上述Lambda表达式的输入参数的数量为0,因此,该Lambda表达式的左边部分的一对小括弧不能被省略。右边是一个表达式

例2:1个参数情况、语句块

#region 1个参数

Action<int> b = m => { int n = m * 2; Console.WriteLine(n); };//此处参数m的括号可以省略

b(2);

#endregion

上述Lambda表达式的输入参数省略了一对小括弧,它与“(m)=> { int n = m * 2; Console.WriteLine(n); };是等效的。右边是语句块,那么该语句块必须被"{"和"}"包围,还有return语句不能省略花括号。

例3:多个参数、语句块

#region 多个参数

Action<int,int> c = (m,n) => { int s = m * n; Console.WriteLine(s); };//此处参数的括号不能省略

c(2,3);

#endregion

六、匿名方法、Lambda表达式应用巩固举例

1、匿名方法与Lambda的替

static void Main(string[] args)

{

//Func<int, int, int, int> ad = M2;

#region 有参数有返回值的匿名方法

Func<int, int, int, int> ad = delegate(int n1, int n2, int n3)//该匿名方法实际上与下面的有名方法M2一样

{

return n1 + n2 + n3;

};

int result = ad(12, 10, 8);

Console.WriteLine(result);

#endregion

#region 有参数有返回值的lambda表达式

Func<int, int, int, int> ad2 = (x, y, z) => { return x + y + z; };

int r = ad2(10, 20, 30);

Console.WriteLine(r);

#endregion

Console.ReadKey();

}

static int M2(int n1, int n2, int n3)

{

return n1 + n2 + n3;

}

说明:匿名方法、lambda表达式运行时最终都会编译成方法

2定义一个能接收参数个数可变有返回值的委托

public delegate int Adddelegate(params int[] arr);//定义一个能接收参数个数可变且有返回值的委托

static void Main(string[] args)

{

#region 接收参数个数可变的lambda表达式

Adddelegate ad = (arr) =>

{

for (int i = 0; i < arr.Length; i++)

{

Console.WriteLine(arr[i]);

}

return arr.Sum();

};

int x = ad(1, 2, 3, 4, 5);

Console.WriteLine(x);

Console.ReadKey();

#endregion

}

3lambda表达式在泛型集合中的应用

示例:打印出泛型集合中大于6的元素。

static void Main(string[] args)

{

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 89, 10, 11, 12, 13, 14, 15 };

//第一种写法自己定义方法

IEnumerable<int> ie = list.Where(cs); //var

//第二种写法用匿名方法

//IEnumerable<int> ie = list.Where(delegate(int n)

//{

//    return n > 6;

//}

//    );//where里面需要一个方法作为参数(有1个int类型参数,返回值为bool类型)

//第三种写法使用lambda表达式

//IEnumerable<int> ie = list.Where(n => { return n > 6; });

foreach (var item in ie)

{

Console.WriteLine(item);

}

Console.ReadKey();

#endregion

}

static bool cs(int n)

{

return n > 6;

}

七、Linq简介

LINQ的全称是Language Integrated Query,中文译成“语言集成查询”。LINQ是一种查询技术,有LINQ to SQL、LINQ to Object、LINQ to ADO.NET、LINQ to XML、LINQ to EF等。

LINQ与直接SQL语句比较:

(1)SQL数据库技术是一门相对比较复杂深奥的技术,不是人人都懂,而LINQ To SQL比较简单(实际上底层都对数据库操作进行了封装,架构了数据访问层)

(2)直接写SQL语句,如果有问题,只有到运行时才知道

(3)LINQ To SQL可以很好的防止注入式攻击

(4)Linq是面向对象的查询,主要在程序内部使用(比如查找所需的数据),比使用DataReader读取数据等方便多了;直接SQL是面向关系型数据库的查询

(5)从运行效率上来说性能不如直接SQL语句,但是开发效率提高了。

要学习LINQ首先就要学习LINQ查询表达式。

LINQ的查询由3基本部分组成:获取数据源,创建查询,执行查询。

// 1.获取数据源

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

// 2.创建查询

var numQuery = from num in numbers

where num % 2 == 0

select num*10;

//与SQL语句比较下

//string ql=”select StuName from Student where ID>1”

// 3.执行查询

foreach (var num in numQuery)

{

Console.WriteLine(num);

}

在 LINQ 中,查询的执行与查询本身截然不同;换句话说,如果只是创建查询变量,则不会检索任何数据。

Linq的数据源要求必须实现IEnumerable或IEnumerable<T>接口,数组隐式支持这个接口。numQuery叫做查询变量,它存储了一个查询表达式。注意,声明查询变量并不会执行查询,真正的执行查询延迟到了foreach语句中。

查询表达式必须以from子句开头,以select或group子句结束。第一个from子句和最后一个select子句或group子句之间,可以包含一个或多个where子句、let子句、join子   句、orderby子句和group子句,甚至还可以是from子句。它包括8个基本子句,具体说明如下所示。

●from子句:指定查询操作的数据源和范围变量。

●select子句:指定查询结果的类型和表现形式。

●where子句:指定筛选元素的逻辑条件。

●let子句:引入用来临时保存查询表达式中的子表达式结果的范围变量。

●orderby子句:对查询结果进行排序操作,包括升序和降序。

●group子句:对查询结果进行分组。

●into子句:提供一个临时标识符。join子句、group子句或select子句可以通过该标识符引用查询操作中的结果。

●join子句:连接多个用于查询操作的数据源。

八、Form子句

创建一个LINQ表达式必须要以from子句开头。

例1:单个Form子句

string[] values = { "中国", "日本", "美国", "菲律宾", "越南" };

//查询包含“国”的字符串

// IndexOf查询参数字符串在父串中首次出现的位置,没有返回-1

var valueQuery = from v in values

where v.IndexOf("国") > 0

select v;

foreach (var v in valueQuery)

{

Console.WriteLine(v);

}

Console.ReadKey();

在这个LINQ表达式的from子句中,v叫做范围变量,values是数据源。v的作用域存在于当前的LINQ表达式,表达式以外不能访问这个变量。where用来筛选元素,select用于输出元素。这里的范围变量v和foreach语句中的隐式变量v都可以由编译器推断出其类型。

例2:复合Form子句

在查询数据源中,元素的属性是一个集合时,可以使用复合from子句对这个属性集合查询。比如,一个客户,可能有多个电话。

class CustomerInfo

{

public string Name { get; set; }

public int Age { get; set; }

public List<string> TelTable { get; set; }

}

static void Main(string[] args)

{

formExpDemo();

Console.ReadKey();

}

static void formExpDemo()

{

List<CustomerInfo> customers = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, TelTable=new List<string>{"1330708****","1330709****"}},

new CustomerInfo{ Name="上官飘飘", Age=17, TelTable=new List<string>{"1592842****","1592843****"}},

new CustomerInfo{ Name="诸葛菲菲", Age=23, TelTable=new List<string>{"1380524****","1380525****"}}

};

//查询包含电话号码1592842****的客户

var query = from CustomerInfo ci in customers//ci

from tel in ci.TelTable

where tel.IndexOf("1592842****") > -1

select ci;

foreach (var ci in query)

{

Console.WriteLine("姓名:{0} 年龄:{1}", ci.Name, ci.Age);

foreach (var tel in ci.TelTable)

{

Console.WriteLine("          电话:{0}", tel);

}

}

}

九、where子句select子句

1where子句

where子句的作用就是筛选元素,除了开始和结束位置,where子句几乎可以出现在LINQ表达式的任意位置。一个LINQ表达式中可以有where子句,也可以没有;可以有一个,可以有多个;多个where子句之间的关系相当于逻辑“与”,每个where子句可以包含1个或多个逻辑表达式,这些条件成为“谓词”,多个谓词之间用布尔运算符隔开,比如逻辑“与”用&&,逻辑“或”用||,而不是用SQL中的AND或OR。

class CustomerInfo

{

public string Name { get; set; }

public int Age { get; set; }

public string Tel { get; set; }

}

List<CustomerInfo> clist = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},

new CustomerInfo{ Name="令狐冲", Age=23, Tel ="1380524****"}

};

//查询名字是3个字或者姓“令”的,但年龄大于20的客户

var query = from customer in clist

where (customer.Name.Length == 3 || customer.Name.Substring(0, 1) == "令") && customer.Age > 20

select customer;

foreach (var ci in query)

{

Console.WriteLine("姓名:{0} 年龄:{1} 电话:{2}", ci.Name, ci.Age, ci.Tel);

}

2select子句

例1:最简单的select就是直接输出from子句建立的那个范围变量:

#region 简单的select示例

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

var query = from n in arr

select n;  //select n*10;对象.属性

#endregion

例2:对查询结果进行投影(转换)。下面查询表达式查询arr数组中的每一个元素,查询结果转换为一个集合对象的两个属性值:ID和Name,它在select子句中由匿名对象初始化器创建。每一个对象的ID属性的值是当前元素的值、Name属性的值为元素的值的字符串的表现形式。

#region 对查询结果进行投影(转换)

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

var query = from n in arr

select new

{

ID = n,

Name = n.ToString()

};

foreach (var item in query)

{

Console.WriteLine(item.ID+"  张"+item.Name);

}

Console.ReadKey();

#endregion

十、Group子句into子句及orderby子句

1Group子句

LINQ表达式必须以from子句开头,以select或group子句结束,所以除了使用select子句外,也可以使用guoup子句来返回元素分组后的结果。group子句用来将查询结果分组,并返回一对象序列。这些对象包含零个或更多个与该组的key值匹配的项。

注意:每一个分组都不是单个元素,而是一个序列(也属于集合)。序列的元素类型为IGrouping<TKey,TElement>(必须以Group子句结束的LINQ表达式,分组结果类型才为序列,序列的元素类型为IGrouping<TKey,TElement>)

List<CustomerInfo> clist = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},

new CustomerInfo{ Name="欧阳锦鹏", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官无忌", Age=23, Tel ="1380524****"}

};

//按照名字的前2个字进行分组

var query = from customer in clist

group customer by customer.Name.Substring(0, 2);

//foreach (IGrouping<string, CustomerInfo> group in query)

foreach (var group in query)

{

Console.WriteLine("分组键:{0}", group.Key);

foreach (var ci in group)

{

Console.WriteLine("姓名:{0} 电话:{1}", ci.Name, ci.Tel);

}

Console.WriteLine("***************************************");

}

2into子句

into子句可以用来创建一个临时标识符,将group、join或select子句的结果存储到这个标识符中。

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

var query = from n in arr

where n > 1 && n < 6

group n by n % 2 into g

from sn in g

select sn;

foreach (var item in query)

{

Console.WriteLine(item);

}

3orderby子句(中间无空格

orderby子句可使返回的查询结果按升序或者降序排序。升序由关键字ascending指定,而降序由关键字descending指定。

注意:orderby子句默认排序方式为升序。

示例1:

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

var query = from n in arr

where n > 1 && n < 6

orderby n descending

select n;

示例2:

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

var query = from n in arr

where n > 1 && n < 6

orderby n % 2 ascending, n descending

select n;

n%2:按照升序排序;n:按照降序排序。

注意:n%2排序关键字优先级大于n排序关键字。因此,该查询表达式的结果首先按照n%2排序关键字升序排序,然后再按照n排序关键字降序排序。第一个排序关键字后的"ascending"可以省略。因为默认排序方式为升序。

十一、let子句join子句

1let子句

let子句用于在LINQ表达式中存储子表达式的计算结果。即let子句创建一个范围变量来存储结果,变量被创建后,不能修改或把其他表达式的结果重新赋值给它。此范围变量可以在后续的LINQ子句中使用。

List<CustomerInfo> clist = new List<CustomerInfo> {

new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},

new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},

new CustomerInfo{ Name="郭靖", Age=17, Tel ="1330708****"},

new CustomerInfo{ Name="黄蓉", Age=17, Tel ="1300524****"}

};

//姓“郭”或“黄”的客户

var query = from customer in clist

let g = customer.Name.Substring(0, 1)

where g == "郭" || g == "黄"

select customer;

foreach (var ci in query)

{

Console.WriteLine("姓名:{0} 年龄:{1} 电话:{2}", ci.Name, ci.Age, ci.Tel);

}

 

//where customer.Name.Substring(0, 1) == "郭" || customer.Name.Substring(0, 1) == "黄"

2join子句

join子句用来连接两个数据源,即设置两个数据源之间的关系。join子句支持以下3种常见联接方式。

内部联接:要求两个数据源都必须存在相同的值,即两个数据源都必须存在满足联接关系的元素。类似于SQL语句中的inner join子句。

分组联接:包含into子句的join子句。

左外部联接:元素的链接关系必须满足联接中的左数据源,类似于SQL语句中的left join子句。

内部连接示例:

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

int[] arrb = new int[] { 0, 2, 4, 6, 8 };

var query = from a in arra

where a < 7

join b in arrb on a equals b

select a;

上一篇:(转)Android 中LocalBroadcastManager的使用方式


下一篇:javascript:算法之for循环