委托
委托概述
委托是存有对某个方法的引用的一种引用类型变量。定义方法的类型,可以把一个方法当作另一方法的参数。所有的委托(Delegate)都派生自 System.Delegate 类。委托声明决定了可由该委托引用的方法。
# 声明委托类型
委托类型声明与方法类似,可以理解为方法的类型,它与方法声明不同的地方:
- 以delegate关键字开头
- 没有方法主体
delegate void ShowInfo();//可带参数,可不带参数
它不需要在类内部声明,因为它是类型声明,委托可指向一个与其具有相同标签的方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
delegate void ShowInfo();
public class Program
{
static void Main(string[] args)
{
ShowInfo showinfo = ShowInfo;//把签名赋值给委托变量
showinfo?.Invoke();//调用委托,可指向相同标签的方法
}
static void ShowInfo()
{
Console.WriteLine("打印ShowInfo方法");
}
}
}
运行结果:
创建委托实例
法一
第一种是使用带new关键字进行创建,操作组成如下:
- 委托类型名称
- 一组圆括号,其中参数列表为成员的方法的名称,该方法可以是实例方法也可以是静态方法
MyDel delVar;//声明委托类型的变量
MyDel delVar= new MyDel(实例方法);//创建委托并保存引用
MyDel delVar= new MyDel(静态方法);//创建委托并保存引用
法二
可以使用快捷语法,仅由方法说明符组成,因为在方法名称和其相对应的委托类型之间存在隐式转换,可以理解为方法赋值给委托变量
delVar = 实例方法;//创建委托并保存引用
delVar = 静态方法;//创建委托并保存引用
委托的调用
可以通过两种方式调用委托。一种是像调用方法一样调用委托,另外一种是使用委托的Invoke方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
delegate void Show();
public class Test
{
//静态方法
public static void Print1()
{
Console.WriteLine("打印静态方法");
}
//实例方法
public void Print2()
{
Console.WriteLine("打印实例方法");
}
}
public class Program
{
static void Main(string[] args)
{
Test test = new Test();
//1、调用方法一样调用委托
Show show = test.Print2;//实例方法赋值给委托变量
show();//调用委托
Show show2 = Test.Print1;//静态方法赋值给委托变量
show2();//调用委托
//2、使用委托的Invoke方法
show?.Invoke();//使用Invoke和空条件运算符
show2?.Invoke();
}
}
}
委托的多播
委托对象可使用 “+” 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。“-” 运算符可用于从合并的委托中移除委托。
匿名方法
匿名方法提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中您不需要指定返回类型,它是从方法主体内的 return 语句推断的。
匿名方法表达式的语法包含如下组成部分:
- delegate关键字
- 参数列表,如果语句快没有使用任何参数则可以省略
- 语句快,它包含了匿名方法的代码
delegate ( 参数 ) {语句块};
案例
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
delegate void Show();
delegate int Add(int a, int b);
public class Program
{
static void Main(string[] args)
{
//不带参数
Show show = delegate
{
Console.WriteLine("打印匿名方法");
};
show();
//带参数
Add add = delegate(int a, int b)
{
int c = a + b;
Console.WriteLine("和为多少:" + c);
return c;
};
add(1,2);
Console.ReadKey();
}
}
}
运行结果:
Lambda表达式
在匿名方法中,delegate关键字有点多余,因为编译器已经指定我们在将方法赋值给委托,因此我们可以利用Lambda表达式删除delegate关键字。在参数列表和匿名方法主体之间放置Lambda运算符=>。Lambda运算符读作"goes to"。如下代码演示这种转换。
MyDel del = delegate(int x) {return x+1};//匿名方法
MyDel del = (int x) =>{return x+1};//Lambda表达式
上面看起来简洁,但是只省略6个字符,然后,编译器可以推断更多的信息,因此我们可以进一步简化。
- 编译器可以从委托声明指定委托参数的类型,因此Lambda表达式可以省略参数的类型。如del1
-
- 如果只有一个隐式类型参数还可以省略圆括号。如del2
- Lambda表达式运行表达式的主体是语句块或表达式,如果语句块包含了返回语句,则可以省略return关键字。如del3
MyDel del = delegate(int x) {return x+1};//匿名方法
MyDel del1 = (x) =>{return x+1};//Lambda表达式
MyDel del2 = x =>{return x+1};//Lambda表达式
MyDel del3 = x =>x+1;//Lambda表达式
Action 和Func
Action和Func都是.net内置的委托,可以使用他们以参数形式传递方法。他们都支持0-16个参数,然后Action没有返回值类型,Func有返回值类型,Func最后一个参数为返回值类型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public class Program
{
static void Main(string[] args)
{
#region
{
//不带参数
Action act1 = () => { Console.WriteLine("打印"); };
act1();
//带1个参数
Action<int> act4 = a => { Console.WriteLine("a="+a); };//这里不能省略{}
act4(2);
//不带参数,带返回值
Func<int> func1 = () => { return 1; };
func1();
//带1个参数,带带返回值
Func<int, int> func2 = a =>
{
int b = a + 1;
Console.WriteLine("b=" + b);
return b;
};
func2(2);
}
#endregion
Console.ReadKey();
}
}
}