可以当作指针,指向某个(某些)方法。
作用:将方法作为参数传递给另一个方法。本可以直接调用方法,但是使用委托将要执行的方法交给另一个方法来执行。
1.基本使用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
//定义委托类型,参数、返回值与被委托的方法相同
delegate void Del(string name);
class Program
{
static void Main(string[] args)
{
Program p = new Program();
//将方法作为参数传入,不同参数执行不同的方法
p.Test("张三",SayHiChinese);
}
public void Test(string name, Del delSayHi)
{
//为委托传入参数,执行委托
delSayHi(name);
}
public static void SayHiChinese(string name)
{
Console.WriteLine(name+"用中文说:嗨");
Console.ReadLine();
}
public static void SayHiEnglish(string name)
{
Console.WriteLine(name + "用英文说:Hi");
Console.ReadLine();
}
}
}
注意:在执行委托时传入参数。
也可以不使用Test(string name, Del delSayHi)方法,直接为委托添加要执行的方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
//定义委托类型,参数、返回值与被委托的方法相同
delegate void Del(string name);
class Program
{
static void Main(string[] args)
{
//为委托添加方法的两种方法
//Del delSayHi = new Del(SayHiEnglish);
Del delSayHi = SayHiEnglish;
//多播委托
delSayHi += SayHiChinese;
//为委托传入参数,执行委托即执行所有添加的方法
delSayHi("张三");
}
public void Test(string name, Del delSayHi)
{
//为委托传入参数,执行委托
delSayHi(name);
}
public static void SayHiChinese(string name)
{
Console.WriteLine(name+"用中文说:嗨");
Console.ReadLine();
}
public static void SayHiEnglish(string name)
{
Console.WriteLine(name + "用英文说:Hi");
Console.ReadLine();
}
}
}
题外话:线程也是将方法作为参数传递给构造函数。
2.使用匿名函数:只是用一次
不需要定义SayHiChinese(string name)和SayHiEnglish(string name)方法,在调用时实参部分直接写一个带SayHiChinese(string name)或SayHiEnglish(string name)方法体的实参委托。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
//定义委托类型,参数、返回值与被委托的方法相同
delegate void Del(string name);
class Program
{
static void Main(string[] args)
{
Program p = new Program();
//匿名函数
p.Test("张三", delegate (string name) { Console.WriteLine(name + "用中文说:嗨"); Console.ReadLine(); });
}
public void Test(string name, Del delSayHi)
{
//为委托传入参数,执行委托
delSayHi(name);
}
}
}
甚至不需要定义Test(string name, Del delSayHi)方法,直接定义委托,为委托添加方法体,最后执行委托:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
//定义委托类型,参数、返回值与被委托的方法相同
delegate void Del(string name);
class Program
{
static void Main(string[] args)
{
//匿名函数
//不使用Test()方法,定义委托,为委托添加方法体
Del delSayHi = delegate (string name)
{
Console.WriteLine(name + "用中文说:嗨");
Console.ReadLine();
};
//传入参数,执行委托
delSayHi("张三");
}
}
}
等价于:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 委托
{
//定义委托类型,参数、返回值与被委托的方法相同
delegate void Del(string name);
class Program
{
static void Main(string[] args)
{
Del delSayHi = (string name) => { Console.WriteLine(name + "用中文说:嗨"); Console.ReadLine(); };
//传入参数,执行委托
delSayHi("张三");
}
}
}
3.泛型委托
//未完待续
4.Lambda表达式
Lambda表达式是匿名函数,常用作委托,方便简洁。
Lambda表达式可以访问到外部变量。
无参数无返回值:
Del del = delegate(){};
//等价于
Del del = () =>{};
有参数无返回值:
Del del = delegate(string name){};
//等价于
Del del = (string name) =>{};
有参数有返回值:
Del del = delegate(string name){return name};
//等价于
Del del = (string name) =>{return name};
移除集合中大于4 的元素:
List<int> list = new List<int>(){1,2,3,4,5,6,7,8,9};
list.RemoveAll(n => n > 4);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo
{
class Lambda1
{
delegate string Del(string s);
static void Main(string[] args)
{
//fun1();
//fun2();
//执行委托(相当于匿名方法)
fun3("BeiJing 2013", s =>
{
if (s.Contains("2013"))
{
s = s.Replace("2013", "2014");
}
return s;
});
Console.ReadLine();
}
private static void fun1()
{
//lambda运算符“=>” 的左边是参数列表,右边是lambda变量的方法的实现代码。
//没有参数(),一个参数没有()直接写参数,多个参数使用(int x, string s...)
//一行代码可省略{}
Del myDel = n =>
{
string s = n + " " + "World";
return s;
};
string str = myDel("Hello");
Console.WriteLine(str);
}
private static void fun2()
{
List<string> citys = new List<string>()
{
"BeiJing",
"ShangHai",
"Tianjin",
"GuangDong"
};
//查找集合中第一个长度大于7的元素
Console.WriteLine(citys.First(c => c.Length > 7));
}
private static void fun3(string str, Func<string, string> func)
{
Console.WriteLine(func(str));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo
{
class Lambda2
{
private delegate int twoparams(int p1, int p2);
static void Main(string[] args)
{
Show();
Console.ReadLine();
}
static void Perform(twoparams tdel)
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
int result = tdel(i, j);
Console.Write("f({0},{1})={2}", i, j, result);
if (j != 5)
Console.Write(" ,");
}
Console.WriteLine();
}
}
static void Show()
{
twoparams test;
test = Tdel;
Console.WriteLine("a+b");
Perform((p1, p2) => p1 + p2);
Console.WriteLine("a*b");
Perform(
delegate (int p1, int p2) { return p1 * p2; }
);
Console.WriteLine("2*a*b");
Perform(Tdel);
Console.WriteLine("2*a*b-22222");//22222纯属为了方便区分,在IL中查看
Perform(test);
}
private static int Tdel(int p1, int p2)
{
return p1 * p2 * 2;
}
}
}
这里用了4种方式来调用:
1.Perform(((p1, p2) => p1 + p2));使用lambda表达式;
2.Perform((delegate (int p1, int p2){ return p1* p2;}));使用匿名函数;
3.Perform(Tdel); 给方法传递一个匹配委托的方法,似乎一个方法不是一个委托, 但因为其满足委托的签名,是可行的,编译器同样可以将其编译成一个委托实例。
4.Perform(test); 这是这个实例中唯一一个满足方法参数的,twoparams test; 创建一个委托实例, 并给它提供一个方法test = Tdel;
5.系统内置委托类型
Action委托:可以有参数,没有返回值。只能执行无返回值的方法。
没有参数的Action委托:
//委托添加方法
Action a1 = Add;
a1 += Sub;
//执行委托的两种方法
a1();
a1.Invoke();
public void Add()
{
int a = 10;
int b= 20;
Console.WriteLine("a+b=",a+b);
}
public void Sub()
{
int a = 10;
int b= 20;
Console.WriteLine("a-b=",a-b);
Console.ReadLine();
}
有参数的Action委托:
//委托添加方法
Action<int,int,int> a1 = Add;
//执行委托的两种方法
a1(1,2,3);
a1.Invoke(1,2,3);
public void Add(int a,int b,int c)
{
Console.WriteLine("{1},{2},{3}",a,b,c);
}
Func<>委托:可以有参数,有返回值。<>中只有一个类型时,表示方法返回值类型;<>中只有多个类型时,表示返回值类型,最后一个表示方法返回值类型,前几个表示参数类型。
//Func委托,两个int类型的参数,一个string类型的返回值
Func<int, int, string> fun = Add;
//执行委托的两种方法
//string result = fun(1,2);
string result = fun.Invoke(1,2);
Console.WriteLine(result);
Console.ReadLine();
public static string Add(int a,int b)
{
return (a + b).ToString();
}
6.使用委托跨窗体传值
场景:Form1中有一个Labe和button1,点击button1创建Form2。
Form2中有一个TextBox和button2,点击button2将TextBox的内容传递给Lebal。
实现方法:Form1中写一个ShowMeg方法,点击button1时,将该方法传递给Form2。
Form1中代码:
public void ShowMeg(string str)
{
label.Text = str;
}
public void button1_Click(object o,EventArgs e)
{
Form2 from2 = new Form2(ShowMeg);
from2.Show();
}
Form1中有显示方法,没有值;Form2中有值,没有显示方法。
Form2中代码:
public delegate void DelTest(string str)
public class Form2:Form1
{
//定义委托类型的引用
public DelTest _del;
public Form2(DelTest del)
{
this._del=del; //调用构造函数时给委托添加方法,即_del=ShowMeg
initializeComponent();
}
}
public void button2_Click(object o,EventArgs e)
{
//执行委托,即给ShowMeg()方法传参数并执行该方法
_del(textBox1.Text);
}