委托
基本定义
委托是一种类类型,是引用类型的一种。它是一种特殊类型的类,体现在以下两点:
- 功能比较特殊:一般情况下,类都是反映现实中的一些事物,而委托类型的实例是用来‘包裹’的一些方法,以委托类型实例间接地调用这些方法。例如有时写程序时,程序的上下文是固定的,但是在某个关键部分需要调哪个函数不确定,就可以通过委托进行间接调用,可替换调用,让程序能够更换调用函数,且不造成两个函数的紧耦合。
- 申明起来比较特殊:不需要class关键字,使用delegate关键字,且类似函数的申明,它具有返回值类型,参数列表,且必须与所‘包裹’的函数的返回值类型和参数列表保持一致。
示例
最基本的委托,‘包裹’一个函数,如下:
using System;
namespace Combine
{
class Program
{
static void Main(string[] args)
{
MyDele dele1 = new MyDele(M1);//dele1这个变量引用着一个MyDele类型的实例,这个实例里‘包裹’着M1这个方法
dele1.Invoke();
}
static void M1()
{
Console.WriteLine("M1 is called");
}
}
delegate void MyDele();
}
‘包裹’多个函数,如下:
using System;
namespace Combine
{
class Program
{
static void Main(string[] args)
{
MyDele dele1 = new MyDele(M1);//dele1这个变量引用着一个MyDele类型的实例,这个实例里‘包裹’着M1这个方法
dele1 += M1;//此时‘包裹’了两个M1方法,也为多播委托
dele1.Invoke();
Console.WriteLine("===================");
MyDele dele2 = new MyDele(M1);
dele2 += (new Student()).SayHello;
dele2(); //同时调用了M1方法和SayHello方法
}
static void M1()
{
Console.WriteLine("M1 is called");
}
}
class Student
{
public void SayHello()
{
Console.WriteLine("Hello, I'm a student");
}
}
delegate void MyDele();
}
带有参数的委托,如下:
using System;
namespace Combine
{
class Program
{
static void Main(string[] args)
{
MyDele dele1 = new MyDele(Add);
int res = dele1.Invoke(100,200);
Console.WriteLine(res);
}
static int Add(int a,int b)
{
return a + b;
}
}
delegate int MyDele(int a,int b);
}
泛型委托
示例:自定义泛型委托,引用有返回值的方法,如下:
using System;
namespace Combine
{
class Program
{
static void Main(string[] args)
{
MyDele<int> deleAdd = new MyDele<int>(Add);
int res = deleAdd.Invoke(100,200);
Console.WriteLine(res);
MyDele<double> deleMul = new MyDele<double>(Mul);
double res2 = deleMul(10, 5);
Console.WriteLine(res2);
}
static int Add(int a,int b)
{
return a + b;
}
static double Mul(double a, double b)
{
return a * b;
}
}
delegate T MyDele<T>(T a,T b);
}
我们必须自己创建委托类型吗
.net framework 有大量预先申明好的泛型委托,有两大类,一大类为没有返回值类型的Action,一大类为有返回值类型的Func,如下:
using System;
namespace Combine
{
class Program
{
static void Main(string[] args)
{
Action action = new Action(M1);
action();
Action<string> action1 = new Action<string>(SayHello);
action1("Tim");
Func<int, int, int> func = new Func<int, int, int>(Add);
Console.WriteLine(func(100, 200));
Func<double, double, double> func1 = new Func<double, double, double>(Mul);
Console.WriteLine(func1(3, 4));
}
static void M1()
{
Console.WriteLine("M1 is called");
}
static void SayHello(string name)
{
Console.WriteLine($"Hello,{name}");
}
static int Add(int a,int b)
{
return a + b;
}
static double Mul(double a, double b)
{
return a * b;
}
}
}
Lambda表达式
基本定义
Lambda起源于希腊字母‘λ’,它具有两个作用:
- 匿名方法,一般用于临时使用的方法
- Inline方法
示例
匿名方法使用示例,如下:
namespace Combine
{
class Program
{
static void Main(string[] args)
{
Func<int, int, int> func = new Func<int, int, int>((int a,int b)=> { return a + b; });
Console.WriteLine(func(100,200));
}
}
}
可以对以上代码进行升级,省略匿名函数的形参数据类型,如下:
Func<int, int, int> func = new Func<int, int, int>((a, b)=> { return a + b; });
如何把一个lambda表达式赋值给一个委托类型变量
对上述代码继续进行升级,去掉创建委托实例,直接把lambda表达式赋值给委托类型的变量,如下:
Func<int, int, int> func = (a, b)=> { return a + b; };//以后工作中常用的语法
如何把一个lambda表达式‘喂’给一个委托类型参数
*将lambda表达式作为函数调用的实参‘喂’给委托类型参数,如下:
using System;
namespace Combine
{
class Program
{
static void Main(string[] args)
{
DoSomeCalc<int>((a, b) => { return a * b;}, 100, 200);
}
static void DoSomeCalc<T>(Func<T, T, T> func,T x, T y)
{
T res = func(x, y);
Console.WriteLine(res);
}
}
}
由于参数100,200为int类型,C#可以自己推断出DoSomeCalc泛型函数的类型为int类型,所以<int>也可省略,也叫**泛型委托的类型参数推断**,甚至return也可以省略,如下:
DoSomeCalc((a, b) =>a * b, 100, 200);
LINQ
基本定义
LINQ全称为:.NET Language Integrated Query,即把SQL的查询集成到.NET中,也可以查询集合,平时在工作中大部分用来查询数据库。
示例
参考上节案例使用‘Entity Framework访问数据库示例’,EF也叫做ORM:object->relational mapping,连接好数据库后,可以不用在SQL Server写查询语句,直接使用LINQ进行查询,对上节案例Book表中所有的Name进行筛选,使用Select()方法。如下:
using System;
using System.Linq;
namespace Bookstore.Client
{
class Program
{
static void Main(string[] args)
{
var dbContext = new BookstoreEntities();
var allBooksName = dbContext.Books.Select(b=>b.Name).ToList();
//通过LINQ的Select方法把Books的Name都筛选出来。
foreach (var bookName in allBooksName)
{
Console.WriteLine(bookName);
}
}
}
}
使用Where(),All(),Any(),GroupBy()举例,如下:
using System;
using System.Linq;
namespace Bookstore.Client
{
class Program
{
static void Main(string[] args)
{
var dbContext = new BookstoreEntities();
var allBooksName = dbContext.Books.Where(b=>b.Name=="Book_001").Select(b=>b.Name).ToList();
//筛选表中Name是Book_001的名称
foreach (var book in allBooksName)
{
Console.WriteLine(book);//Book_001
}
var yesOrNo = dbContext.Books.All(b => b.ID == 1);//筛选是否所有的ID为1
Console.WriteLine(yesOrNo);//false
var yesOrNo1 = dbContext.Books.Any(b => b.ID == 1);//筛选是否有一个ID为1
Console.WriteLine(yesOrNo1);//true
var groups = dbContext.Books.GroupBy(b => b.Price).ToList();//筛选相同价位的数量
foreach (var g in groups)
{
Console.WriteLine("Price:{0}\tCount{1}",g.Key,g.Count());
}
var count = dbContext.Books.Count(b => b.ID == 1);//筛选ID为1的数量
Console.WriteLine(count);
}
}
}
更多的LINQ语句方法可以Google查询C# LINQ Methods的MSDN文档。