[C#2] 2-匿名方法

简介: 1.匿名方法应用和机制 先看一段代码(C#1.0): 1 //这里加了参数 2 public delegate void MyDelegate(object sender, EventArgs e); 3 class Program 4 { 5 static void Main() 6 { 7 new Program().

1.匿名方法应用和机制

先看一段代码(C#1.0):

 1 //这里加了参数<为了说明delegate关键字后面的参数列表>
 2 public delegate void MyDelegate(object sender, EventArgs e);
 3 class Program
 4 {
 5     static void Main()
 6     {
 7         new Program().function();
 8     }
 9     private void function()
10     {
11         MyDelegate md1 = new MyDelegate(MyMethod);
12         md1(this, EventArgs.Empty);
13     }
14     private void MyMethod(object sender, EventArgs e)
15     {
16         Console.WriteLine("C#1.0写法");
17     }
18 }

到了C#2.0时就可以省略掉起到为多委托声明的书写,直接内联方式写MyMethod方法:

private void function()
{
    MyDelegate md2 = delegate { Console.WriteLine("C#2.0写法"); };
    md2(this,EventArgs.Empty);
}

难道真的省去了中间的方法了吗?看看IL代码:

发现多了一个《'<function>b__0'》的静态方法,如下是此方法代码:

//编译器还是产生了一个方法,这个方法名很怪<以使用匿名方法的所在方法名开头>
//注意delegate { Console.WriteLine("C#2.0写法"); };的delegate 后面我们没有写
//参数<所以匿名方法内部将用不到参数了>,编译器产生了些命名奇怪的参数
.method private hidebysig static void  '<function>b__0'(object A_0,
    class [mscorlib]System.EventArgs A_1) cil managed
{
    //下面这两行表示这些代码是编译器产生的,而不是我们手动写的
    .custom instance void[mscorlib]System.Runtime.CompilerServices
    .CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    // 代码大小       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      bytearray (43 00 23 00 32 00 2E 00 30 00 99 51 D5 6C )       // C.#.2...0..Q.l
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
} // end of method Program::'<function>b__0'

在delegate关键字后面可以不指定参数[结果就是你无法使用参数,但是参数还是实实在在的存在的,只是它的命名是编译器决定的,很奇怪的名字,你拿不到], 但是如果指定参数,则必须全部指定,拿上面的例子说,我只用到了[object sender和EventArgs e中的一个参数],只指定一个行不行,答案是不行的,你要么不指定,要么全部指定, 从委托的签名来说这点很好理解

匿名方法允许我们以内联的方式简化代码书写[本质还是相同的,并没有性能的提升,只是把我们以前做的工作由编译器代做了]。 注意到编译器生成的这个方法是个静态方法,看过有些文章说用在实例方法内部的匿名方法会产生一个实例方法,说的不完整, 我做过几个测试,结果是在前提条件是在实例方法中,当你用到实例成员时,编译器才会产生实例方法,当你没有用到时, 编译器产生一个静态方法。当然在静态方法中使用匿名方法则产生一个"匿名"的静态方法,而不会是实例方法了。

2.匿名方法的中的"外部变量"

这个外部变量指的是匿名方法所在的方法里的局部变量,对与匿名方法来说称作外部变量, 改写下上面的代码[只改了function这个方法,其他没动]:

private void function()
{
    int i = 10;
    MyDelegate md2 = delegate
    {
        i++;
        Console.WriteLine("C#2.0写法");
    };
    md2(this, EventArgs.Empty);
}

虽然声明的这个i没做什么实质性的工作,但是它却使编译器做了很多额外的工作,看图:

我们的《'<function>b__0'》跑到一个内部类里去了,编译器调用到外部变量产生了一个内部类[私有密封的类]! 而把外部变量作为了这个类的一个共有字段,我还原下改写的那个function方法[注:把上图用友好点的代码写一下]:

 1 private void function()
 2 {
 3     Temp tempClass = new Temp();
 4     tempClass.i = 10;
 5     MyDelegate md2 = new MyDelegate(tempClass.TempMethod);
 6     md2(this, EventArgs.Empty);
 7 }
 8 private sealed class Temp 
 9 {
10     public int i;
11 
12     public void TempMethod(object sender, EventArgs e)
13     {
14         i++;
15         Console.WriteLine("C#2.0写法");
16     }
17 }

这个开销还是蛮大的[另外i的值也变的不确定了,慎用外部变量!],用new一个类实现外部变量的传递。 外部变量的生命周期被延长了,一直持续到引用该匿名方法的委托符合垃圾回收的条件为止。对i的引用是在创建该委托时捕获的。 匿名方法不能访问外部范围的ref和out参数。

3.总结

总结:C#2.0中的匿名方法仅仅是编译器简化我们创建委托实例的过程,是一种语法糖,与C#1.0中的写法没有本质的区别。另外匿名方法不是方法...

作者: Blackheart
目录
相关文章
|
2月前
|
开发框架 .NET 程序员
C# 去掉字符串最后一个字符的 4 种方法
在实际业务中,我们经常会遇到在循环中拼接字符串的场景,循环结束之后拼接得到的字符串的最后一个字符往往需要去掉,看看 C# 提供了哪4种方法可以高效去掉字符串的最后一个字符
220 0
|
26天前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
113 65
|
5月前
|
数据采集 数据可视化 测试技术
C#生成Selenium测试报告:实用方法与技巧
在C#中使用Selenium进行自动化测试时,结合代理IP和ExtentReports能增强测试安全性和报告质量。安装必备工具如Selenium WebDriver、NUnit和ExtentReports。在测试设置中,配置代理(如亿牛云爬虫代理)以隐藏IP,通过ChromeOptions定制UserAgent,并添加Cookie。测试代码示例展示了如何打开网页、执行搜索并生成详细的测试报告。使用ExtentReports可创建可视化测试结果,便于团队分析。
C#生成Selenium测试报告:实用方法与技巧
|
24天前
|
存储 C#
【C#】大批量判断文件是否存在的两种方法效率对比
【C#】大批量判断文件是否存在的两种方法效率对比
27 1
|
24天前
|
C#
C#的方法的参数传递
C#的方法的参数传递
12 0
|
24天前
|
数据可视化 程序员 C#
C#中windows应用窗体程序的输入输出方法实例
C#中windows应用窗体程序的输入输出方法实例
24 0
|
2月前
|
C#
C#一分钟浅谈:Lambda 表达式和匿名方法
本文详细介绍了C#编程中的Lambda表达式与匿名方法,两者均可用于定义无名函数,使代码更简洁易维护。文章通过基础概念讲解和示例对比,展示了各自语法特点,如Lambda表达式的`(parameters) =&gt; expression`形式及匿名方法的`delegate(parameters)`结构。并通过实例演示了两者的应用差异,强调了在使用Lambda时应注意闭包问题及其解决策略,推荐优先使用Lambda表达式以增强代码可读性。
38 8
|
3月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
67 0
|
3月前
|
C#
C# async await 异步执行方法
C# async await 异步执行方法
49 0
|
3月前
|
C# 图形学
小功能⭐️C#控制小数点后位数的方法
小功能⭐️C#控制小数点后位数的方法