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.要输出系统当前时间到控制台,2.要输出系统当前是星期几,3.要把系统时间写入到文本文件等)
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与总结
从上例可以看出委托一般是在一个方法(1)的一大段程序中间“挖个坑”,这个坑用来执行另一个方法(2),而这个方法(2)是动态的,可以根据需要调用不同的方法到方法(1)中。
需求:对字符串的处理经常要发生变化,比如在字符串两端加“=”、加“★”,把字符串字母全部转换为大写。
namespace _03委托的基本应用练习与总结
{
    //定义一个委托(委托是一种数据类型,接受方法的数据类型)
    public delegate string GetStringDelegate(string str);

    public class TestClass
    {
        public void ChangeStrings(string[] strs, GetStringDelegate GetString)
        {
            for (int i = 0; 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 = 0; 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 + "=";
        }
委托认识的总结:
委托是一种数据类型,像类一样的一种数据类型。一般都是直接在命名空间中定义。
定义委托时,需要指明返回值类型、委托名与参数列表,这样就能确定该类型的委托能存储(接受)什么样的方法。
使用委托
(1)声明委托变量
(2)委托是一个引用类型,就像类一样,所以当声明委托变量后,如果不赋值则该委托变量为null。所以在使用委托变量前最好做非空校验if(weituo!=null)

四、泛型委托Action与Action<T>
1、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、自己写泛型委托
例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(1);
            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>3、Action<T>委托(泛型版本)
Action<T>委托的泛型版本是一个无返回值,但是参数个数及类型可以改变的委托。
例子3:
class Program
    {
        static void Main(string[] args)
        {
            Action<string> action1 = M1;
            action1("内置无返回值的泛型委托");
            Action<int> action2 = M1;
            action2(12);
            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)。

 

1

 

2

 

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方法(绑定第一个方法不能用+=复制,因为开始actionnull,所以只能用=赋值),下面再给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里面需要一个方法作为参数(有1int类型参数,返回值为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 XMLLINQ 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)。

 

1

 

2

 

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方法(绑定第一个方法不能用+=复制,因为开始actionnull,所以只能用=赋值),下面再给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里面需要一个方法作为参数(有1int类型参数,返回值为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 XMLLINQ 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;

posted @ 2018-08-01 12:39  WhiteSpace  阅读(892)  评论(0编辑  收藏  举报