委托,匿名函数和lambda表达式

很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一下自己对他的印象,顺便把自己的感悟和想法写出来,以便自己能有更深的理解,由于本人水平有限,也欢迎大家多多探讨,有问题大家一起解决一起进步。

MSDN上面对委托的定义是:delegate 是表示对具有特定参数列表和返回类型的方法的引用的类型。在我看来委托的特性主要在:

1.把一个方法当做一个参数传递给另一个函数。这样可以做到方法的扩展,比如我们在比较两个同种类型的数据(两个相同类的对象)时,我们只需要向比较方法中传递比较的对象和比较的规则,这个规则就可以是一个委托的形式去传入,我们不清楚不同类型的对象的比较的方法,我们在比较的时间只需要将对象和对应的比较规则传进去就好。看下面代码:

namespace DelegateTest
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Person p1 = new Person {Name = "p1", Age = 19};
            Person p2 = new Person {Name = "p2", Age = 22};
           //传入比较的对象和具体的比较规则
            ComparePerson(p1, p2, ComparePersonRule);
        }
        //定义委托
        public delegate bool CompareRule(int x, int y);
      //这个方法就是委托指向的具体的比较的方法
        public static bool ComparePersonRule(int x, int y)
        {
            return x > y;
        }
        //在比较peson类型的数据时,不需要知道具体的比较规则,只需要传入一个委托,具体的比较由委托 compareRule指向的具体方法来实现
        public static void ComparePerson(Person p1, Person p2, CompareRule compareRule)
        {
            if (compareRule(p1.Age, p2.Age))
            {
                Console.WriteLine(p1.Name + "比" + p2.Name + "年纪大!");
                Console.ReadKey();
            }
            else
            {
                Console.WriteLine(p1.Name + "比" + p2.Name + "年纪小!");
                Console.ReadKey();
            }
        }

        public class Person
        {
            public int Age { get; set; }
            public string Name { get; set; }
        }
    }
}

再换比较对象的类型时,只要换不同的委托实体就行,这样可以极大的扩展代码的可用性。

2.委托用于回调函数,回调函数就是把一个方法的传给另外一个方法去执行。在C#有很多回调函数,比如异步操作的时候。这里先举个例子:

namespace DelegateCallbackTest
{
    /// <summary>
    /// 委托
    /// </summary>
    /// <param name="s1"></param>
    /// <param name="s2"></param>
    /// <returns></returns>
    public delegate string ProcessDelegate(string s1, string s2);
    class Program
    {

        static void Main(string[] args)
        {
            /*  调用方法  */
            Test t = new Test();

            string r1 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process1));

            Console.WriteLine(r1);

            Console.ReadKey();
        }
    }
    public class Test
    {
        public string Process(string s1, string s2, ProcessDelegate process)
        {
            return process(s1, s2);
        }

        public string Process1(string s1, string s2)
        {
            return s2 + s1;
        }
    }
}

这里委托的方法最后在Test的Process方法里面执行,这就是一种最简单的回调。在C#里面有好多委托回调的例子,这里就不再说了。

3.多播委托,事件的实现就是通过多播委托来实现的,一个+=和一个—=,形成一个委托链,一个一个的执行委托指向的方法。

说到委托自然而然离不开匿名函数,我感觉匿名函数就是为了方便写委托而产生的,或许是我对它的理解还不到位,匿名方法是C#2.0引入的一个新特性,它允许开发者内联(inline)声明自己的函数代码而无须使用委托函数(delegate function。匿名方法通常在1. 需要一个临时方法,该方法使用次数极少;2. 这个方法的代码很短,甚至可能比方法声明都短的情况下使用。你可以把C# 匿名方法想象为一个实现与委托进行关联这项功能的便捷途径。如果同时看一下匿名方法实现和命名方法实现所取得IL结果,你会发现这两者之间的差别非常小。当编译器碰到匿名方法的时候,它会在类里面创建一个命名方法,并将它与委托进行关联。所以匿名方法在运行期间与命名方法的性能非常类似——性能的增加体现在开发人员的生产效率上,而不是运行期间的执行上。在 C# 1.0 中,您通过使用在代码中其他位置定义的方法显式初始化委托来创建委托的实例。               C# 2.0 引入了匿名方法的概念,作为一种编写可在委托调用中执行的未命名内联语句块的方式。  C# 3.0 引入了 Lambda 表达式,这种表达式与匿名方法的概念类似,但更具表现力并且更简练。  这两个功能统称为“匿名函数”。  通常,针对 .NET Framework 版本 3.5 及更高版本的应用程序应使用 Lambda 表达式。

下面的示例演示了从 C# 1.0 到 C# 3.0 委托创建过程的发展:



class Test
{
    delegate void TestDelegate(string s);
    static void M(string s)
    {
        Console.WriteLine(s);
    }

    static void Main(string[] args)
    {
        // Original delegate syntax required
        // initialization with a named method.
        TestDelegate testDelA = new TestDelegate(M);

        // C# 2.0: A delegate can be initialized with
        // inline code, called an "anonymous method." This
        // method takes a string as an input parameter.
        TestDelegate testDelB = delegate(string s) { Console.WriteLine(s); };

        // C# 3.0. A delegate can be initialized with
        // a lambda expression. The lambda also takes a string
        // as an input parameter (x). The type of x is inferred by the compiler.
        TestDelegate testDelC = (x) => { Console.WriteLine(x); };

        // Invoke the delegates.
        testDelA("Hello. My name is M and I write lines.");
        testDelB("That‘s nothing. I‘m anonymous and ");
        testDelC("I‘m a famous author.");

        // Keep console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    Hello. My name is M and I write lines.
    That‘s nothing. I‘m anonymous and
    I‘m a famous author.
    Press any key to exit.
 */
下面是在MSDN上的摘要:

Lambda 表达式是一种可用于创建委托表达式目录树类型的匿名函数。通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数。 Lambda 表达式对于编写 LINQ 查询表达式特别有用。 若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。             例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值。

=>    运算符具有与赋值运算符 (=) 相同的优先级并且是右结合运算(参见“运算符”文章的“结合性”部分)。

Lambda 在基于方法的 LINQ 查询中用作标准查询运算符方法(如 Where)的参数。

使用基于方法的语法在 Enumerable 类中调用 Where 方法时(如在 LINQ to Objects 和 LINQ to XML 中一样),参数是委托类型 System.Func<T, TResult>。  使用 Lambda 表达式创建该委托最为方便。  例如,当你在 System.Linq.Queryable 类中调用相同的方法时(如在 LINQ to SQL 中一样),参数类型为 System.Linq.Expressions.Expression<Func>,其中 Func 是最多具有十六个输入参数的任何一个 Func 委托。  同样,Lambda 表达式只是一种非常简洁的构造该表达式目录树的方式。  尽管事实上通过 Lambda 创建的对象具有不同的类型,但 Lambda 使得 Where 调用看起来类似。

在上一个示例中,请注意委托签名具有一个 int 类型的隐式类型输入参数,并返回 int。  可以将 Lambda 表达式转换为该类型的委托,因为该表达式也具有一个输入参数 (x),以及一个编译器可隐式转换为 int 类型的返回值。(以下几节中将对类型推理进行详细讨论。)使用输入参数 5 调用委托时,它将返回结果 25。

isas 运算符的左侧不允许使用 Lambda。

适用于匿名方法的所有限制也适用于 Lambda 表达式。

可见lambda是一种更加方便的匿名函数,可以说完全是为了委托而产生的。以上只为自己个人愚见,还望能和大家多多交流。


 

委托,匿名函数和lambda表达式

时间: 2024-10-22 16:06:07

委托,匿名函数和lambda表达式的相关文章

3 委托、匿名函数、lambda表达式

委托.匿名函数.lambda表达式 在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法.C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式 // 声明一个委托 delegate void Printer(string s); class TestClass { static void Main() { //lambda表达式 Printer pp = x => { Console.WriteLine(&quo

C# 匿名函数和Lambda 表达式

匿名函数是一个"内联"语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. 共有两种匿名函数,以下主题中分别讨论了这些函数: Lambda Expressions (C# Programming Guide). ' data-guid="7df86c4348dea57abb774138a7de05b8">Lambda 表达式(C# 编程指南) . 匿名方法(C# 编程指南) 说明

C#语法之匿名函数和Lambda表达式

上一篇博客主要是对委托和事件做了一小结,这篇是在上一篇博客的基础上对匿名函数和Lambda表达式小结.还是接着上一篇说起,在上一篇中也说了委托是一种数据结构,主要是解决让函数作为参数的问题.在使用委托时首先要声明代理,然后实例化,并将委托对象和已定义好的函数关联上,最后调用.这里与已定义好的函数关联的事情,如果函数是经常使用的也还好,如果不是经常使用的可能只调用一次,那这岂不是老费劲了.就是能不能在使用的时候定义下呢?于是乎有了匿名方法. 一.匿名方法的使用. 匿名方法的使用步骤和委托的使用步骤

C#匿名委托,匿名函数,lambda表达式

一.类型.变量.实例之间的关系. 类型>变量>实例 类型可以创建变量,实体类可以创建实例,实例可以存储在变量里. 二.委托使用过程: 1.定义委托(写好签名): 2.创建委托变量: 3.在委托变量里放函数(相同的签名). 事件:用预先定义好的委托(EventHandle)的定义的变量(接收两个参数). 窗体里自带一个委托变量:我们做的就是给这个变量追加函数. 给窗体Load事件添加一个函数 public partial class Form1 : Form { public Form1() {

委托、匿名函数、Lambda表达式和事件的学习

委托: 还记得C++里的函数指针么?大家可以点击这里查看一下以前的笔记.C#的委托和C++中的函数指针效果一致. 当我们需要将函数作为对象进行传递和使用时就需要用到委托. 下面我们看一个例子: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Test 8 { 9 cl

委托、匿名函数与Lambda表达式初步

(以下内容主要来自<C#本质论第三版>第十二章委托和Lambda表达式) 一.委托续 上上周五看了看委托,初步明白了其是个什么,如何定义并调用.上周五准备看Lambda表达式,结果发现C#本质论中顺带讲了讲委托,所以在这,继续写一下委托. 首先,考虑如下问题: 需要对一个数组排序,先假设是数字,要求由大到小,很快我们便想到了冒泡排序 1 public static void bubblSort(int[] items) 2 { 3 int i, j, temp; 4 if (items ==

12_Python的(匿名函数)Lambda表达式_Python编程之路

Python作为一门高级语言,与很多编程语言一样都具有匿名函数这一特征 匿名函数,也就Lambda表达式,通俗来讲就是不用命名的方法,直接定义,直接用即可 创建匿名函数需要用到Lambda关键字,下面我们通过一个简单的匿名函数的创建熟悉匿名函数 lambda a,b : a + b 这个表达式返回的值是a加上b的值,他需要传入两个参数,也就是a,b,同时还需要一个表达式,这样才能构成一个完整的匿名函数 通过代码完善这一部分的理解 In [1]: func = lambda a,b : a+b I

C#委托、匿名方法和Lambda表达式

工作中经常用到Lambda表达式,简单好用代码清晰,虽然用的也算上手,但忘记了当年大学课堂上学它的时候老师讲的它跟委托和匿名方法的关系,今天抽了时间简单的了解了一下,在这里做个总结. 1 什么是委托 public delegate string DelegateTest(string a); public static string GetA(string a) { return a; } static void Main(string[] args) { DelegateTest d = ne

匿名方法,Lambda表达式,高阶函数

原文:匿名方法,Lambda表达式,高阶函数 匿名方法 c#2.0引入匿名方法,不必创建单独的方法,因此减少了所需的编码系统开销. 常用于将委托和匿名方法关联,例如 1. 使用委托和方法关联: this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);private void btnRefresh_Click(object sender, EventArgs e){    BindData();} 2. 使用委