目录
1、lambda表达式
1.1 闭包、使用表达式外部变量
2、lambda表达式的委托订阅、取消
2.1、订阅
2.1、取消订阅
?
1、lambda表达式
使用lambda表达式给委托订阅方法,在线实现代码,格式如下:
lambda运算符“=>”的左边列出需要的参数类型,右边赋予lambda表达式变量的方法实现代码。
//具有返回类型
Func<string,string> mylambda = param=>{
代码实现
}
//不具返回类型
Action<string> mylambda = param=>{
代码实现
}
//多个参数
Func<string,int,string> mylambda = (param1,param2)=>{
代码实现
}
//多个参数
Action<string,int> mylambda = (param1,param2)=>{
代码实现
}
1.1 闭包、使用表达式外部变量
lambda表达式可以访问当时的外部变量,并存到表达式内部。
string value= "abc";
Func<string,string> mylambda = param=> value + param;
对于闭包的理解我们先看下面几个例子:
List<Func<int>> funcs = new List<Func<int>>();
int[] value = {1, 2, 3,4};
for (int i = 0; i < 3; i++)
{
funcs.Add(() => { return value[i]; });
}
foreach (var item in funcs)
{
Console.WriteLine(item().ToString());
}
输出:
3
3
3
?输出:3,3,3
List<Func<int>> funcs = new List<Func<int>>();
for (int i = 0; i < 3; i++)
{
funcs.Add(() => { return i; });
}
foreach (var item in funcs)
{
Console.WriteLine(item().ToString());
}
输出:
3
3
3
?输出:3,3,3
List<Func<int>> funcs = new List<Func<int>>();
int[] value = {1, 2, 3,4};
foreach (var val in value)
{
funcs.Add(() => { return val; });
}
foreach (var item in funcs)
{
Console.WriteLine(item().ToString());
}
输出:
1
2
3
?输出:1,2,3
在循环中的lambda使用外部变量时,lambda会保持外部变量的地址,即使该变量不是引用类型,但在输出时都是同一地址的变量。
前两个例子中使用了 i 索引,每个循环中 i 的地址不变,变的只是 i 的地址所指向的值(最后一次赋值 :3)
第三个例子中,每个val 都有不同的地址,也指向不同的值,所以每个变量都按照预期被保持下来。
2、lambda表达式的委托订阅、取消
2.1、订阅
//先声明一个委托
Action<string,string> GetSignal;
//列表
List<string> Datas = {"1","2","3","4"};
//保存lambda表达式的列表,后面取消订阅时使用
List<Action<string,string>> actionList = new List<Action<string,string>>();
//1:订阅lambda表达式 不利于保存订阅的lambda表达式
foreach(var data in Datas)
{
GetSignal += (str1,str2)=>
{
Console.WriteLine(str1+data+str2);
};
}
//2:订阅lambda表达式 并保存lambda表达式到列表
foreach(var data in Datas)
{
Action<string,string> action = (str1,str2)=>
{
Console.WriteLine(str1+data+str2);
};
GetSignal += action;
actionList.Add(action);
}
2.1、取消订阅
//先声明一个委托
Action<string,string> GetSignal;
//列表
List<string> Datas = {"1","2","3","4"};
//保存lambda表达式的列表,后面取消订阅时使用
List<Action<string,string>> actionList = new List<Action<string,string>>();
//1:订阅lambda表达式 不利于保存订阅的lambda表达式
foreach(var data in Datas)
{
GetSignal += (str1,str2)=>
{
Console.WriteLine(str1+data+str2);
};
}
//2:订阅lambda表达式 并保存lambda表达式到列表
foreach(var data in Datas)
{
Action<string,string> action = (str1,str2)=>
{
Console.WriteLine(str1+data+str2);
};
GetSignal += action;
actionList.Add(action);
}
//3:取消订阅
foreach(var action in actionList)
{
GetSignal -= action;
}
但是在使用时发现:这样无法正常取消,原因是lambda表达式不是函数,我的理解是它只是一个表达关系,只有在使用时才会生成相应的函数,所以绑定之后的方法和lambda表达式不是同一个对象。因此无法正常取消。
正确的方法应该是获取绑定之后的方法,并存到列表中用于后续取消订阅。如下:
//先声明一个委托
Action<string,string> GetSignal;
//列表
List<string> Datas = {"1","2","3","4"};
//保存lambda表达式的列表,后面取消订阅时使用
List<Action<string,string>> actionList = new List<Action<string,string>>();
//1:订阅lambda表达式 不利于保存订阅的lambda表达式
foreach(var data in Datas)
{
GetSignal += (str1,str2)=>
{
Console.WriteLine(str1+data+str2);
};
var action = GetSignal.GetInvocationList();
var actiontosave = action[action.Length-1];//最后一个方法
actionList.Add((Action<string, string>)actiontosave);
}
//2:订阅lambda表达式 并保存lambda表达式到列表
foreach(var data in Datas)
{
Action<string,string> action = (str1,str2)=>
{
Console.WriteLine(str1+data+str2);
};
GetSignal += action;
var action = GetSignal.GetInvocationList();
var actiontosave = action[action.Length-1];//最后一个方法
actionList.Add((Action<string, string>)actiontosave);
}
//3:取消订阅
foreach(var action in actionList)
{
GetSignal -= action;
}
?
|