.Net学习难点讨论系列10 - 匿名方法,Lambda表达式及其对局部变量的影响

匿名方法是C# 2.0中简化委托模型的一种语法糖。Lambda表达式是C# 3.0新增的语法特性,其在匿名方法的基础上更进一步,但其本质都是相同的,我们通过一段代码来分析对比这个语言特性。它们分别是在C#2.0与C# 3.0中的主要写法。

delegate void DelWithoutParam ();

delegate void DelWithParams (int intparam, string strparam);

delegate string DelParamRetVal (int param);

 

class Program

{

public DelWithoutParam delTestNoParam;

public DelWithParams delTestWithParam;

public DelParamRetVal delTestParamRetVal;

 

public event DelWithoutParam evtTestNoParam;

public event DelWithParams evtTestWithParam;

 

static void Main(string [] args)

{

Program p = new Program ();

// 订阅处理函数

p.SubEvent();

p.ShowVarible();

 

Console .Read();

// 依次触发委托与事件

p.delTestNoParam();

p.delTestWithParam(1, "ParamInDelobj" );

// 只会返回第二个调用函数的返回值

Console .WriteLine(p.delTestParamRetVal(10086));

 

p.evtTestNoParam();

p.evtTestWithParam(1, "ParamInEvt" );

 

//Console.ReadLine();

Thread .Sleep(100000);

}

 

public void SubEvent()

{

// 不具有参数的委托声明,在 delegate 后面加上 "()"

delTestNoParam += delegate ()

{

Console .WriteLine("del - 匹配不带参数的委托的方法被在匿名函数中调用 " );

};

 

evtTestNoParam += delegate ()

{

Console .WriteLine("evt - 匹配不带参数的委托的方法被在匿名函数中调用 " );

};

 

// 匿名方法出现之前调用委托处理

evtTestNoParam += new DelWithoutParam (Program_evtTestNoParam);

 

//lambda 表达式

evtTestNoParam += () => Console .WriteLine("evt - 匹配不带参数的委托的方法被在 lambda 表达式中调用 " );

 

// 有返回值的委托

delTestParamRetVal += delegate (int p)

{

return " 有返回值委托,在匿名函数中处理: " + p.ToString();

};

 

delTestParamRetVal += (q) => { return " 有返回值委托,在 lambda 表达式中处理: " + q.ToString(); };

}

 

public void ShowVarible()

{

delTestWithParam += delegate (int int_p, string str_p)

{

Console .WriteLine("del - 匹配参数 int:{0},string:{1} 的委托的方法被在匿名函数中调用 " , int_p, str_p);

};

 

evtTestWithParam += delegate (int int_p, string str_p)

{

Console .WriteLine("evt - 匹配参数 int:{0},string:{1} 的委托的方法被在匿名函数中调用 " , int_p, str_p);

};

 

delTestWithParam += delegate

{

Console .WriteLine("del - 匹配任何参数的委托的方法被在匿名函数中调用 " );

};

 

//lambda 表达式

evtTestWithParam += (i, s) => Console .WriteLine("evt - 匹配参数 int:{0},string:{1} 的委托的方法被在 lambda 表达式中调用 " , i, s);

}

 

/* 辅助函数 */

void Program_evtTestNoParam()

{

Console .WriteLine("evt - 传统方式调用:匹配不带参数的委托的方法被在函数中调用 " );

}

}

 

 

这篇文章主要介绍的一个问题是匿名方法中使用类成员或局部变量以及对匿名函数外部局部变量或参数的影响(对于lambda表达式同理,代码中有体现)。上述代码改造一下如下,我们通过这段代码来分析这个特性。

    下列代码中需要注意的是匿名函数捕获变量的一个特殊情况(加粗代码),即局部变量的初始化问题,通过代码中两个对比应该可以很清楚的看出原因。

delegate void DelWithoutParam ();

delegate void DelWithParams (int intparam, string strparam);

 

class Program

{

public DelWithoutParam delTestNoParam;

public DelWithParams delTestWithParam;

 

public string classmember = " 这是类成员 " ;

 

static void Main(string [] args)

{

Program p = new Program ();

// 订阅处理函数

p.SubEvent();

p.ShowVarible();

 

Console .Read();

// 依次触发委托与事件

p.delTestNoParam();

p.delTestWithParam(1, "ParamInDelobj" );

 

//Console.ReadLine();

Thread .Sleep(100000);

}

 

public void SubEvent()

{

// 匿名函数 - 调用成员变量示例

delTestNoParam += delegate ()

{

Console .WriteLine(" 匿名函数中调用成员变量 :{0}" , classmember);

};

 

//lambda 表达式 - 调用成员变量示例

delTestNoParam += () => Console .WriteLine("lambda 表达式中调用成员变量 :{0}" , classmember);

 

int pd = 1;

int pl = 2;

// 匿名函数 - 调用局部变量

delTestNoParam += delegate ()

{

// 由于匿名函数内部使用了局部变量,局部变量的生命周期增长,而不是立即被垃圾回收。

Console .WriteLine(" 匿名函数中调用局部变量 :{0}" , pd);

};

//lambda 表达式 - 调用局部变量

delTestNoParam += () => Console .WriteLine("lambda 表达式中调用局部变量 :{0}" , pl);

 

// 调用局部变量的特殊情况 - 匿名函数

for (int i = 0; i < 3; i++)

{

int j = i * 2 + 1;

delTestNoParam += delegate ()

{

Console .Write(" 匿名函数 - 变量定义于循环内,输出: " );

Console .Write(j + ", " );

Console .WriteLine();

};

}

 

int k;

for (int i = 0; i < 3; i++)

{

k = i * 2 + 1;

delTestNoParam += delegate ()

{

Console .Write(" 匿名函数 - 变量定义于循环外,输出: " );

Console .Write(k + ", " );

Console .WriteLine();

};

}

 

// 调用局部变量的特殊情况 - lambda 表达式

for (int i = 0; i < 3; i++)

{

int j = i * 2 + 1;

delTestNoParam += () =>

{

Console .Write("lambda 表达式 - 变量定义于循环内,输出: " );

Console .Write(j + ", " );

Console .WriteLine();

};

}

 

int m;

for (int i = 0; i < 3; i++)

{

m = i * 2 + 1;

delTestNoParam += () =>

{

Console .Write("lambda 表达式 - 变量定义于循环外,输出: " );

Console .Write(m + ", " );

Console .WriteLine();

};

}

}

 

public void ShowVarible()

{

delTestWithParam += delegate (int int_p, string str_p)

{

Console .WriteLine("del - 匹配参数 int:{0},string:{1} 的委托的方法被在匿名函数中调用 " , int_p, str_p);

};

 

//lambda 表达式

delTestWithParam += (i, s) => Console .WriteLine("evt - 匹配参数 int:{0},string:{1} 的委托的方法被在 lambda 表达式中调用 " , i, s);

}

}

 

下面引用MSDN对匿名函数/Lambda表达式变量范围问题的总结:

下列规则适用于 Lambda 表达式中的变量范围:

  • 捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。
  • 在外部方法中看不到 Lambda 表达式内引入的变量。
  • Lambda 表达式无法从封闭方法中直接捕获 ref 或 out 参数。
  • Lambda 表达式中的返回语句不会导致封闭方法返回。
  • Lambda 表达式不能包含其目标位于所包含匿名函数主体外部或内部的 goto 语句、break 语句或 continue 语句。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值