C# 匿名方法

简介: 每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默。我眼中的程序员大多都不爱说话,默默承受着编程的巨大压力,除了技术上的交流外,他们不愿意也不擅长和别人交流,更不乐意任何人走进他们的内心,他们常常一个人宅在家中! 废话说多了,咱进入正题: 上一节我们谈到了匿名变量,本节我们学习匿名方法。

每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默。我眼中的程序员大多都不爱说话,默默承受着编程的巨大压力,除了技术上的交流外,他们不愿意也不擅长和别人交流,更不乐意任何人走进他们的内心,他们常常一个人宅在家中!

废话说多了,咱进入正题:

上一节我们谈到了匿名变量,本节我们学习匿名方法。

来自MSDN上的说法是这样的

在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法。  C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式。  有一种情况下,匿名方法提供了 Lambda 表达式中所没有的功能。  您可使用匿名方法来忽略参数列表。  这意味着匿名方法可转换为具有各种签名的委托。  这对于 Lambda 表达式来说是不可能的。  有关 lambda 表达式的更多特定信息,请参见 Lambda 表达式(C# 编程指南)。 

根据MSDN上的说法,我们知道先有委托,再有匿名方法,最后到Lanbda表达式。因此,在讲解C#匿名方法之前,我们有必要说说C#委托这个东东。

 

委托是一个类型安全的对象,它指向程序中另一个以后会被调用的方法(或多个方法)。通俗的说,委托是一个可以引用方法的对象,当创建一个委托,也就创建一个引用方法的对象,进而就可以调用那个方法,即委托可以调用它所指的方法。

  • 如何使用委托?

1、定义委托类型

[访问修饰符]delegate 返回类型 委托名(形参);

2、声明委托对象

委托名 委托实例名;

3、创建委托对象(确定与哪些方法进行绑定)

委托实例名=new 委托名(某个类的方法)

4、使用委托调用方法

委托实例名(实参)

  • 委托注意事项:

1、委托和方法必须具有相同的参数。

2、委托可以调用多个方法,即一个委托对象可以维护一个可调用方法的列表而不是单独的一个方法,称为多路广播(多播)。

3、使用+=和-=运算实现方法的增加和减少

     下面我们通过一个小例子来讲解下委托,其代码如下(本事例通过计算器(+-*/)讲解简单的委托):

delegate int calculator(int x, int y); //委托类型
        static void Main(string[] args)
        {
            //创建委托对象(确定与哪些方法进行绑定),委托实例名=new 委托名(某个类的方法,本例与加法向绑定
            calculator MYAdd = new calculator(Adding);
            //创建委托对象(确定与哪些方法进行绑定),委托实例名=new 委托名(某个类的方法,本例与减法向绑定
            calculator MYMove = new calculator(Moveing);
            //创建委托对象(确定与哪些方法进行绑定),委托实例名=new 委托名(某个类的方法,本例与乘法向绑定
            calculator MYMultiply = new calculator(Multiply);
            //创建委托对象(确定与哪些方法进行绑定),委托实例名=new 委托名(某个类的方法,本例与除法向绑定
            calculator MYDivide = new calculator(Divide);
            //通过委托执行方法
            int A = MYAdd(4, 4);//8
            int B = MYMove(4, 4);//0
            int C = MYMultiply(4, 4);//16
            int D = MYDivide(4, 4);//1
        }

        /// <summary>
        /// 加法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static int Adding(int x,int y)
        {
            return x + y;
        }
        /// <summary>
        /// 减法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static int Moveing(int x, int y)
        {
            return x - y;
        }
        /// <summary>
        /// 乘法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static int Multiply(int x, int y)
        {
            return x * y;
        }
        /// <summary>
        /// 除法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static int Divide(int x, int y)
        {
            return x / y;
        }

根据上述的事例,大家应该了解简单委托的使用了。

那么,我们更近一步,来说说泛型委托。泛型应该是大家比较熟悉的一种数据类型,泛型委托又是如何和泛型向结合的呢?

再讲泛型委托之前,先说说微软引入泛型的目的及使用泛型的好处。

  •                  为什么要有泛型
  •       假设你是一个方法的设计者,
  •       这个方法有一个传入参数,有一个返回值。
  •       但你并不知道这个参数和返回值是什么类型的,
  •       如果没有泛型,你可能把参数和返回值的类型都设定为Object了
  •       那时,你心里肯定在想:反正一切都是对象,一切的基类都是Object
  •       没错!你是对的!
  •       这个方法的消费者,会把他的对象传进来(有可能会做一次装箱操作)
  •       并且得到一个Object的返回值,他再把这个返回值强制类型转化为他需要的类型
  •       那么这个过程涉及到的装箱拆箱会损耗系统的性能。
  •       那么我们如何把损耗性能避免掉呢?
  •       有泛型之后就可以了!

微软已经为我们事先定义好了三个泛型委托(Predicate,Action,Func),下面我们探讨下这三个委托的不同。

1、Predicate 泛型委托定义如下:

public delegate bool Predicate<in T>(T obj);
这个委托表示的方法需要传入一个T类型的参数,并且需要返回一个bool类型的返回值
代码实例如下:、
static void Main(string[] args)
        {
            //Predicate 泛型委托代表一类具有 一个T类型(通用类型)作为参数并返回BOOL类型的方法
            var B = new Predicate<int>(isbol);
 bool BB=isbol(1);//true }
/// <summary> /// Predicate 泛型委托 /// </summary> /// <typeparam name="?"></typeparam> /// <param name="x"></param> /// <returns></returns> public static bool isbol(int x) { return x > 0; }

2、Action委托定义如下:

   public delegate void Action<T>(T obj,T obj2,...,obj16);      --最多16个参数

 他代表了一类方法,可以有0个到16个输入参数,输入参数的类型是不确定的。此类方法不能有返回值,也就是返回VOID类型的方法。

   代码实例如下:

static void Main(string[] args)
        {
            //Action 他代表了一类方法,可以有0个到16个输入参数,输入参数的类型是不确定的。此类方法不能有返回值,也就是返回VOID类型的方法。
            var B = new Action<int,string,string>(Action_d);
            B(-1,"true","flase");
            Console.ReadKey();
        }

       /// <summary>
        /// Action 泛型委托
       /// </summary>
       /// <typeparam name="?"></typeparam>
       /// <param name="x"></param>
       /// <returns></returns>
        public static void Action_d(int x,string y,string z)
        {
            if (x > 0)
            {
                Console.WriteLine(y);
            }
            else
            {
                Console.WriteLine(z);
            }
        }

3、Func泛型委托 定义如下:

    public delegate T Func<T>(T obj,T obj2,...,obj16);   --最多16个参数

   为了弥补Action泛型委托,不能返回值的不足,.net提供了Func泛型委托,相同的是它也是最多0到16个输入参数,参数类型由使用者确定,不同的是它规定要有一个返回值,返回值的类型也由使用者确定,说白了,就是ACtion委托没有返回值,而FUNC委托具有了返回值,他们都是最多16个参数。

    代码实例如下:

    

static void Main(string[] args)
        {
            //Func 他代表了一类方法,可以有0个到16个输入参数,输入参数的类型是不确定的。此类方法有返回值。
            var B = new Func<int, string,string,string>(Func_d);//注意:<>中最后一个string代表输出类型 
            Console.WriteLine(B(1,"True","False"));
            Console.ReadKey();
        }

       /// <summary>
        /// Predicate 泛型委托
       /// </summary>
       /// <typeparam name="?"></typeparam>
       /// <param name="x"></param>
       /// <returns></returns>
        public static string Func_d(int x,string y,string z)
        {
            if (x > 0)
            {
                return y;
            }
            else
            {
                return z;
            }
        }

学会了C#委托,那么C#匿名方法就显得很简单了!下面和小伙伴们探讨下C#匿名方法的使用!

还记得本篇上述的计算器吧!就是那个加减乘除委托。我们知道,我们在定义好委托后,还需要在定义加减乘数方法,C#引入匿名方法后,我们就不需要在单独写这些方法了,我们只需在匿名方法体内实现我们的业务逻辑即可!

  

delegate int calculator(int x, int y); //委托类型
        static void Main(string[] args)
        {
            //创建委托对象(确定与哪些方法进行绑定),委托实例名=new 委托名(某个类的方法,本例与加法向绑定
            calculator Adding =delegate( int x, int y)
            {
               return x+y;
            };

            calculator Moveing = delegate(int x, int y)
            {
                return x - y;
            };

            calculator Multiply = delegate(int x, int y)
            {
                return x * y;
            };

            calculator Divide = delegate(int x, int y)
            {
                return x / y;
            };
            Adding(4, 4);//8
            Moveing(4, 4);//0
            Multiply(4, 4);//16
            Divide(4, 4);//1
        }

讲解到现在,想必大家对匿名方法有一定的了解了!

下面是参考MSDN上的一些资料如下:

通过使用匿名方法,由于您不必创建单独的方法,因此减少了实例化委托所需的编码系统开销。

例如,如果创建方法所需的系统开销是不必要的,则指定代码块(而不是委托)可能非常有用。  启动新线程即是一个很好的示例。  无需为委托创建更多方法,线程类即可创建一个线程并且包含该线程执行的代码。  

C#
 
void StartThread()
{
    System.Threading.Thread t1 = new System.Threading.Thread
      (delegate()
            {
                System.Console.Write("Hello, ");
                System.Console.WriteLine("World!");
            });
    t1.Start();
}
备注
 
 

匿名方法的参数的范围是“匿名方法块”。

如果目标在块外部,那么,在匿名方法块内使用跳转语句(如 gotobreak 或 continue)是错误的。  如果目标在块内部,在匿名方法块外部使用跳转语句(如 gotobreak 或 continue)也是错误的。  

如果局部变量和参数的范围包含匿名方法声明,则该局部变量和参数称为该匿名方法的“外部”变量。  例如,下面代码段中的 n 即是一个外部变量:  

C#
 
int n = 0;
Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };

外部变量的引用n被认为是捕获在创建委托时。  与本地变量不同,捕获的变量的生存期内扩展,直到引用该匿名方法委托被垃圾回收。  

匿名方法不能访问外部范围的 ref 或 out 参数。

在“匿名方法块”中不能访问任何不安全代码。

在 is 运算符的左侧不允许使用匿名方法。

 好了,截止到现在,匿名方法讲解完毕,如果需要更深入的了解匿名方法,可以找度娘哈!这里仅仅只是简单的介绍!

下一节,我们共同学习拉姆达表达式!lambda说: 一步一个脚印,学好C#基础很重要!

@陈卧龙的博客





 

相关文章
|
3月前
|
开发框架 .NET 程序员
C# 去掉字符串最后一个字符的 4 种方法
在实际业务中,我们经常会遇到在循环中拼接字符串的场景,循环结束之后拼接得到的字符串的最后一个字符往往需要去掉,看看 C# 提供了哪4种方法可以高效去掉字符串的最后一个字符
348 0
|
2月前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
125 65
|
6月前
|
数据采集 数据可视化 测试技术
C#生成Selenium测试报告:实用方法与技巧
在C#中使用Selenium进行自动化测试时,结合代理IP和ExtentReports能增强测试安全性和报告质量。安装必备工具如Selenium WebDriver、NUnit和ExtentReports。在测试设置中,配置代理(如亿牛云爬虫代理)以隐藏IP,通过ChromeOptions定制UserAgent,并添加Cookie。测试代码示例展示了如何打开网页、执行搜索并生成详细的测试报告。使用ExtentReports可创建可视化测试结果,便于团队分析。
C#生成Selenium测试报告:实用方法与技巧
|
1月前
|
JSON 程序员 C#
使用 C# 比较两个对象是否相等的7个方法总结
比较对象是编程中的一项基本技能,在实际业务中经常碰到,比如在ERP系统中,企业的信息非常重要,每一次更新,都需要比较记录更新前后企业的信息,直接比较通常只能告诉我们它们是否指向同一个内存地址,那我们应该怎么办呢?分享 7 个方法给你!
|
1月前
|
C# UED SEO
C# 异步方法async / await任务超时处理
通过使用 `Task.WhenAny`和 `Task.Delay`方法,您可以在C#中有效地实现异步任务的超时处理机制。这种方法允许您在指定时间内等待任务完成,并在任务超时时采取适当的措施,如抛出异常或执行备用操作。希望本文提供的详细解释和代码示例能帮助您在实际项目中更好地处理异步任务超时问题,提升应用程序的可靠性和用户体验。
69 3
|
2月前
|
存储 C#
【C#】大批量判断文件是否存在的两种方法效率对比
【C#】大批量判断文件是否存在的两种方法效率对比
51 1
|
2月前
|
C#
C#的方法的参数传递
C#的方法的参数传递
25 0
|
2月前
|
数据可视化 程序员 C#
C#中windows应用窗体程序的输入输出方法实例
C#中windows应用窗体程序的输入输出方法实例
54 0
|
3月前
|
C#
C#一分钟浅谈:Lambda 表达式和匿名方法
本文详细介绍了C#编程中的Lambda表达式与匿名方法,两者均可用于定义无名函数,使代码更简洁易维护。文章通过基础概念讲解和示例对比,展示了各自语法特点,如Lambda表达式的`(parameters) =&gt; expression`形式及匿名方法的`delegate(parameters)`结构。并通过实例演示了两者的应用差异,强调了在使用Lambda时应注意闭包问题及其解决策略,推荐优先使用Lambda表达式以增强代码可读性。
49 8
|
4月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
100 0