.NET 学习笔记——委托
一、委托
委托是引用类型,因此委托有引用和对象。
(1) 从数据结构来讲,委托是和类一样是一种用户自定义类型。
(2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象。
委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。
delegate void Mydel(int x)
Mydel mydel;
mydel = new Mydel(demo.printlow) //创建委托并保存使用
mydel = new Mydel(静态方法)
mydel = demo.printlow;//创建委托并保存使用
委托可以使用额外的运算符来组合。这个运算最终会创建一个新的委托,其调用列表是两个操作数的委托调用列表的副本的连接。
委托是恒定的,操作数委托创建后不会被改变。委托组合拷贝的是操作数的副本。
MyDel del1 = myObj.MyMethod;
MyDel del2 = SClass.OtherM2;
MyDel del3 = del1 + del2; //组合调用列表,
使用+=为委托添加方法,当使用+=运算符时,实际上是创建了一个新的委托,其调用列表时左边的委托加上右边方法的组合,然后将这个新的委托赋给左边的委托变量;使用-=为委托移除方法,与增加方法一样,其实是创建了一个新的委托。新的委托是旧的委托的副本——只是没有了已被移除方法的引用。
MyDel del = myObj.MyMethod;
del += SClass.OtherM2; // 增加方法
del -= myObj.MyMethod; // 移除方法
#委托调用 用于调用委托的的参数将会用于调用列表的每一个方法(除非有输出参数)。
//delegate void mydelegate(int value);//声明委托类型
delegate void mydelegateprint();//声明委托类型
static void Main(string[] args)
{
Demo1 demo = new Demo1();
//mydelegate mydel;//声明委托变量
mydelegateprint print;
//Random rand = new Random();
// int randdomvalue = rand.Next(99);//生成随机数
//mydel = randdomvalue < 50 ? new mydelegate(demo.PrintLow) : new mydelegate(demo.PrintLow);
//也可以写作
print = demo.test1;
print += demo.test2;
print += demo.test2;
print += demo.test1;
//mydel(randdomvalue); //执行委托
print?.Invoke(); //简化后的委托判断是否为空
Console.ReadKey();
}
public void test1()
{
Console.WriteLine("test1");
}
public void test2()
{
Console.WriteLine("test2");
}
运行结果如下:
有输出参数时:只会返回最后一个带有返回参数的方法的返回值:
delegate int returntestc();
int value = 5;
public int testreturn1()
{
value += 2;
return value;
}
public int testreturn2()
{
value += 3;
return value;
}
public void excute()
{
returntestc returndel = testreturn2;//
returndel += testreturn1;
returndel += testreturn2;
Console.WriteLine("Value;{0}", returndel());
}
运行结果如下:
这里只返回了一个值 ,正常情况下三个被委托方法应该都有返回值,所以返回值应该是三个。
委托方法有多个返回值时可以使用Func<>:
public void excute()
{
Func<int> func = testreturn1;
func += testreturn2;
func += testreturn1;
var funclist = func.GetInvocationList();
foreach (Func<int> f in funclist)
{
Console.WriteLine(f());
}
Console.ReadKey();
}
如果有输入参数还可以使用: Func<入参,输出参数> 。
运行结果如下:
委托匿名方法的语法:delegate (参数列表){ 语句块 }:
匿名方法的参数必须与委托的参数数量、参数类型和位置、修饰符一致;
**当匿名方法不使用参数列表的参数以及委托的参数列表不包含输出参数时,可以以省略匿名函数的参数列表。**如下:
用在匿名方法中的外部变量称为被方法捕获,只要捕获方法还是委托的一部分,即使变量离开了作用域,被捕获的变量也还会一直生效。如下:
delegate void Testdalegate();
public void test3()
{
Testdalegate mydel;
{
int x = 5;
mydel = delegate
{
Console.WriteLine("Value of X:{0}", x);
};
};
//Console.WriteLine("Value of X:{0}", x);//编译报错,x不在作用范围内
mydel?.Invoke();
}
委托的Lambda表达式
lambda表达式的参数必须在参数数量、类型和位置上与委托相匹配。
lambda表达式的参数列表中不一定需要包含类型(隐式类型),除非有ref或者out 参数———此时需要注明参数 类型(显示类型)。
如果只有一个参数,且参数是隐式类型的,周围的圆括号可以省略,否则必须有括号。
如果没有参数,必须使用一组空的圆括号。
lambda表达式由左边的参数部分以及右边的表达式组成。
delegate int Mydelegates(int x);
Mydelegates dele = delegate(int y) { return y + 1; }; //匿名方法
Mydelegates dele1 = (int y) => { return y + 1; }; //lambda表达式
Mydelegates dele2 = ( y ) => { return y + 1; }; //lambda表达式
Mydelegates dele3 = y => { return y + 1; }; //lambda表达式
Mydelegates dele4 = y => y + 1; //lambda表达式