温故而知新:Delegate,Action,Func,匿名方法,匿名委托,事件

一、委托Delegate

一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如

public void HelloWorld()
{
    Console.WriteLine("Hello World!");
}
public void HelloWorld(string name)
{
    Console.WriteLine("Hello ,{0}!", name);
}

但是有些时候,我们希望把一个方法本身当做参数传递给另一个方法,比如

myObject.callMethod(HelloWorld);

在没有委托之前,这是一件极困难的事情,委托出现以后,这就是一件很容易的事情了,简单点讲:委托就是一种能把方法当做参数来使用的类型--当然这个定义跟官方的解释比起来极不严密,但易于理解

要点:
1.委托是一种类型(跟string,int,double...一样是.net的一种基本类型)
2.委托的定义必须与最终被调用的方法保持签名一致

比如:下面代码中的

delegate void D1(); 与 static void HelloWorld1(),我们抛开前面的类型关键字delegate与static,他们的签名都是void X()
void D2(string myName);与void HelloWorld2(string name); void HelloWorld3(string name);它们的签名格式都是 void X(string Y)

3.委托的好处之一在于可以保持签名格式不变的情况下,动态调用不同的处理逻辑(即不同的方法)

想想系统控件中的Button类,系统并不知道按钮按下去时到底会执行怎么样的逻辑(点击后的处理,每个项目可能都不一样,完全由需求决定),但是我们知道每个Button都有一个Click(object sender, EventArgs e)这样的东东,没错,就是委托(当然封装成了另一种衍生类型event),就是这种设计保证了统一的格式,不管你实际开发中想如何处理点击后的逻辑,只要按这个统一的签名来就行了
完整代码演示:

using System;
namespace ActionStudy
{
    class Program
    {

        delegate void D1();
        delegate void D2(string myName);

        static void Main(string[] args)
        {
            D1 d1 = new D1(HelloWorld1);
            d1();

            D2 d2 = new D2(HelloWorld2);
            d2("Jimmy");

            d2 = new D2(HelloWorld3);
            d2("杨俊明");            

            Console.Read();

        }

        static void HelloWorld1()
        {
            Console.WriteLine("Hello World!");
        }

        static void HelloWorld2(string name)
        {
            Console.WriteLine("Hello,{0}!", name);
        }

        static void HelloWorld3(string name)
        {
            Console.WriteLine("你好,{0}!", name);
        }
    }
}

二 、匿名方法(.net2.0开始支持)

在“一、委托Delegate”的演示代码中,我们看到委托调用方法前,至少得先定义一个签名相同的方法,然后才能由委托调用(哪怕是只有一行代码的方法),好象有点烦哦,想偷懒,ok,没问题

using System;
namespace ActionStudy
{
    class Program
    {

        delegate void D1();
        delegate void D2(string myName);

        static void Main(string[] args)
        {
            D1 d1 = delegate
            {
                Console.WriteLine("Hello World!");
            };
            d1();

            D2 d2 = delegate(string name)
            {
                Console.WriteLine("Hello,{0}!", name);
            };

            d2("Jimmy");

            d2 = delegate(string name)
            {
                Console.WriteLine("你好,{0}!", name);
            };

            d2("杨俊明");

            Console.Read();

        }
    }
}

运行效果完全相同,只是省去了方法的单独定义部分

到了.net 3.0这种偷懒的作风更夸张,看下面的代码(利用了Lambda表达式)

using System;
namespace ActionStudy
{
    class Program
    {

        delegate void D1();
        delegate void D2(string myName);

        static void Main(string[] args)
        {           

            D1 d1 = () => { Console.WriteLine("Hello World!"); };
            d1();

            D2 d2 = (string name) => { Console.WriteLine("Hello,{0}!", name); };
            d2("Jimmy");

            d2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
            d2("杨俊明");

            Console.Read();

        }
    }
}

运行效果仍然没变,初次接触者可能感觉很怪,其实我也觉得怪,不过很多大牛们都喜欢这样用,所以至少还是要能看得懂,否则别人会说"你 Out了" :)
三、Action

Action的本质就是委托,看它的定义:

namespace System
{
    // 摘要:
    //     Encapsulates a method that takes no parameters and does not return a value.
    public delegate void Action();
}

namespace System
{
    // 摘要:
    //     Encapsulates a method that takes a single parameter and does not return a
    //     value.
    //
    // 参数:
    //   obj:
    //     The parameter of the method that this delegate encapsulates.
    //
    // 类型参数:
    //   T:
    //     The type of the parameter of the method that this delegate encapsulates.
    public delegate void Action<T>(T obj);
}

当然,还有Action<T1,T2>乃至Action<T1,T2,T3,T4>参数个数从2到4的类型,不过定义都差不多

简单点讲,Action是参数从0到4,返回类型为void(即没有返回值)的委托

using System;
namespace ActionStudy
{
    class Program
    {

        static Action A1;
        static Action<string> A2;

        static void Main(string[] args)
        {
            A1 = new Action(HelloWorld1);
            A1();

            A2 = new Action<string>(HelloWorld2);
            A2("Jimmy");

            A2 = (string name) => { Console.WriteLine("你好,{0}!", name); };
            A2("杨俊明");

            A2 = delegate(string name) { Console.WriteLine("我就是委托,{0} 你说对吗?", name); };
            A2("菩提树下的杨过");          

            Console.Read();

        }

        static void HelloWorld1()
        {
            Console.WriteLine("Hello World!");
        }

        static void HelloWorld2(string name)
        {
            Console.WriteLine("Hello,{0}!", name);
        }

    }

}

四、Func

Func其实也是一个"托"儿,呵呵,不过这个委托是有返回值的。看下定义就知道了:

namespace System
{
    // 摘要:
    //     Encapsulates a method that has no parameters and returns a value of the type
    //     specified by the TResult parameter.
    //
    // 类型参数:
    //   TResult:
    //     The type of the return value of the method that this delegate encapsulates.
    //
    // 返回结果:
    //     The return value of the method that this delegate encapsulates.
    public delegate TResult Func<TResult>();
}

namespace System
{
    // 摘要:
    //     Encapsulates a method that has one parameter and returns a value of the type
    //     specified by the TResult parameter.
    //
    // 参数:
    //   arg:
    //     The parameter of the method that this delegate encapsulates.
    //
    // 类型参数:
    //   T:
    //     The type of the parameter of the method that this delegate encapsulates.
    //
    //   TResult:
    //     The type of the return value of the method that this delegate encapsulates.
    //
    // 返回结果:
    //     The return value of the method that this delegate encapsulates.
    public delegate TResult Func<T, TResult>(T arg);
}

同Action类似,Func的参数从1到5个,有5个不同的重载版本
代码:

using System;
namespace ActionStudy
{
    class Program
    {

        static Func<string> F;
        static Func<DateTime, string> F2;      

        static void Main(string[] args)
        {
            F = new Func<string>(HelloWorld1);
            Console.WriteLine(F());

            F2 = new Func<DateTime, string>(HelloWorld2);
            Console.WriteLine(F2(DateTime.Now));

            Console.Read();

        }

        static string HelloWorld1()
        {
            return "Hello World!";
        }

        static string HelloWorld2(DateTime time)
        {
            return string.Format("Hello World,the time is {0}.", time);
        }

    }
}

五、匿名委托

ok,如果你没有晕的话,再来看一下匿名委托,其实这也是一种偷懒的小伎俩而已
看代码说话:

//F = new Func<string>(HelloWorld1);

其实也可以简写成这样:

F = HelloWorld1;

//F2 = new Func<DateTime, string>(HelloWorld2);

其实也可以简写成这样

F2 = HelloWorld2;

方法直接赋值给委托,这二个类型不同吧???

没错,你会发现编译一样能通过,系统在编译时在背后自动帮我们加上了类似 “= new Func<...>”的东东,所以我们能偷懒一下下,这个就是匿名委托。

如果你细心的话,会发现我们在定义Button的Click处理事件时,通常是这样的:

this.button1.Click += new EventHandler(button1_Click);

但有时候我们也可以写成这样:

this.button1.Click += button1_Click;

这其实就是匿名委托的应用.

六、事件event

其实,这...还是个托儿!

我们来看下按钮Click事件的定义

// 摘要:
//     Occurs when the control is clicked.
public event EventHandler Click;

继续刨根问底,查看EventHandler的定义:

using System.Runtime.InteropServices;

namespace System
{
    // 摘要:
    //     Represents the method that will handle an event that has no event data.
    //
    // 参数:
    //   sender:
    //     The source of the event.
    //
    //   e:
    //     An System.EventArgs that contains no event data.
    [Serializable]
    [ComVisible(true)]
    public delegate void EventHandler(object sender, EventArgs e);
}

看到了吧,就是委托!

转载请注明来自菩提树下的杨过http://www.cnblogs.com/yjmyzz/archive/2009/11/23/1608818.html

时间: 2024-10-10 01:04:06

温故而知新:Delegate,Action,Func,匿名方法,匿名委托,事件的相关文章

c# delegate action func predicate event 匿名函数 lambda

1.delegate 是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类. 与其它的类不同,delegate类能够拥有一个签名 (signature),并且它只能持有与它的签名相匹配的方法的引用. 它所实现的功能与C/C++中的函数指针十分相似.它允许你传递一个类A的方法m 给另一个类B的对象,使得类B的对象能够调用这个方法m.但与函数指针相比,delegate有许多函数指针不具备的优点: 首先,函数指针只能指向静态函 数,而delegate既可以引用静态函数,又可以引用非静态成员函

匿名方法就是委托

当对2个数实现加减乘除,其中的一个解决方案是通过委托来实现.如下: class Program { private delegate int CaculateDel(int num1, int num2); static void Main(string[] args) { CaculateDel caculateDel = Add; Console.WriteLine(caculateDel.Invoke(1,2).ToString()); Console.ReadKey(); } stati

委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件

1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委托代表了具有相同参数列表和返回值的所有函数. [csharp] view plaincopy class Program { delegate int CalculateDelegate(int a, int b); int add(int a, int b) { return a + b; } s

linq和匿名方法、委托、匿名委托、lambda

委托相当于JavaScript中的闭包,c++中的函数指针. c#为了引进这个函数指针,将其进行包装成“委托”,同时将非托管的变成托管的. 1.最初的委托该怎么用 弊端:写的代码量过多,还要写一个显示的方法(Run). 2.匿名委托 直接将方法体赋予委托实例. 3.lambda表达式 s是参数,只有一个参数时可省略小括号:方法体只有一句时,可以省略大括号. 4.还能继续优化吗 原文地址:https://www.cnblogs.com/1016391912pm/p/11978800.html

委托,匿名方法,Lambda,泛型委托,表达式树

一.委托:完成一个委托应分三个步骤://step01:首先用delegate定义一个委托;public delegate int CalculatorAdd(int x, int y);//step02:声明一个方法来对应委托.public int Add(int x, int y){ return x + y;}protected void FrmTest_Load(object sender, EventArgs e){ //step03:用这个方法来实例化这个委托. CalculatorA

委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式

引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到和委托相关的匿名方法.Lambda表达式及泛型委托记录下来,以备复习使用. 委托: 日常工作中,常常见到委托用在具体的项目中.而且委托使用起来相对来说也是非常简单的,下面列举一个委托实例用以说明如何使用委托,代码如下: class Program { public delegate int CalculateDelegate(int x, int y)

.NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以,跟着本篇的步伐,继续来围观. /* 新语法索引 */ 1.自动属性 Auto-Implemented Properties 2.隐式类型 var 3.参数默认值 和 命名参数 4.对象初始化器 与 集合初始化器 { } 5.匿名类 & 匿名方法 6.扩展方法 7.系统内置委托 Func / Acti

匿名类、匿名方法、扩展方法

/* 新语法索引 */ 1.自动属性 Auto-Implemented Properties 2.隐式类型 var 3.参数默认值 和 命名参数 4.对象初始化器 与 集合初始化器 { } 5.匿名类 & 匿名方法 6.扩展方法 7.系统内置委托 Func / Action 8.Lambda表达式 9.标准查询运算符 Standard Query Operator 10.LINQ查询表达式 一.匿名类 1.1 不好意思,我匿了 在开发中,我们有时会像下面的代码一样声明一个匿名类:可以看出,在匿名

[C#] C# 基础回顾 - 匿名方法

C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ≥ C# 3.0 的版本中,我们会用 Lambda 表达式进行取代匿名方法,并且用 Lambda 表达式作为编写内联代码的首选方式,因为它更简洁. 匿名方法是,顾名思义,匿名方法就是没有名称的方法.匿名方法最明显的好处就是:可以降低额外另写一个方法的工作量:另外一个好处就是可以直接访问调用者的变量,