c# 委托声明的地方(可以在类内部可以在类外部)

在C#中使用一个类时,分两个阶段。首先需要定义这个类,即告诉编译器这个类由什么字段和方法组成。然后(除非只使用静态方法)实例化类的一个对象。使用委托时,也需要经过这两个步骤。首先定义要使用的委托,对于委托,定义它就是告诉编译器这种类型的委托代表了哪种类型的方法,然后创建该委托的一个或多个实例。

定义委托的语法如下:

delegate void VoidOperation(uint x);

在这个示例中,定义了一个委托VoidOperation,并指定该委托的每个实例都包含一个方法的细节,该方法带有一个uint参数,并返回void。理解委托的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所代表的方法的全部细节。

提示:
理解委托的一种好方式是把委托的作用当作是给方法签名指定名称。

假定要定义一个委托TwoLongsOp ,该委托代表的函数有两个long型参数,返回类型为double。可以编写如下代码:

delegate double TwoLongsOp(long first, long second);

或者定义一个委托,它代表的方法不带参数,返回一个string型的值,则可以编写如下代码:

delegate string GetAString();

其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate。因为定义委托基本上是定义一个新类,所以可以在定义类的任何地方定义委托,既可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在命名空间中把委托定义为顶层对象。委托和类、接口类似,通常比较多的放在类的外部或命名空间中根据定义的可见性,可以在委托定义上添加一般的访问修饰符:public、 private和 protected等:

public delegate string GetAString();

注意:
实际上,“定义一个委托”是指“定义一个新类”。委托实现为派生于基类System. MulticastDelegate的类,System.MulticastDelegate又派生于基类System.Delegate。C#编译器知道这个类,会使用其委托语法,因此我们不需要了解这个类的具体执行情况,这是C#与基类共同合作,使编程更易完成的另一个示例。

定义好委托后,就可以创建它的一个实例,以存储特定方法的细节。

注意:
此处,在术语方面有一个问题。类有两个不同的术语:“类”表示较广义的定义,“对象”表示类的实例。但委托只有一个术语。在创建委托的实例时,所创建的委托的实例仍称为委托。您需要从上下文中确定委托的确切含义



 delegate、Delegate、MulticastDelegate的区别

1 Delegate:是一个抽象基类,它引用静态方法或引用类实例及该类的实例方法。然而,只有系统和编译器可以显式地从 Delegate 类派生出委托类型。

2 MulticastDelegate:是一个继承于Delegate的类,其拥有一个带有链表格式的委托列表,该列表称为调用列表,在调用多路广播委托时,将按照调用列表中的委托出现的顺序来同步调用这些委托。平常我们声明一个delegate的类型,都是继承于MulticastDelegate类的(注意:不能显式地从此类进行派生。这点与Delegate类是一样的,只有系统和编译器也可以显示地进行派生)。

3 delegate 是一个C#关键字,用来定义一个新的委托类型(继承自MulticastDelegate类)。

 

示例说明

class Program
{

    //这里就是声明了一个新的委托类型GreetingDelegate。

    public delegate void GreetingDelegate(string name);

    public static GreetingDelegate delegate1;
    static void Main(string[] args) 
    {

        //这里声明了委托类型GreetingDelegate的变量delegate1,并注册两个委托到其调用列表中。
        delegate1 += EnglishGreeting; 
        delegate1 += ChineseGreeting;

        //这里进行调用,会依次同步调用注册的上面两个委托对应的方法。
        delegate1("Cupid");

        //这里的输出就能知道委托类型GreetingDelegate实际是继承自MulticastDelegate类。

        Console.WriteLine(typeof(GreetingDelegate).BaseType.FullName); 
    }

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

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

为什么有些场景会用到事件(event)呢?

其实有些场景的话,使用委托就可以解决了的,比如上面的示例。当然,如果一定要用event也可以,把

public static GreetingDelegate delegate1这句换成

public static event GreetingDelegate delegate1;

即加一个event关键字就可以了。 
所以上面的理由只能说明一点:事件就是对委托类型的一种特殊封装。

但为什么还是会出现使用event关键字的场景呢,比如Form的Load事件等。

其真正的特殊性如下

1 事件的设计是从面向对象的角度进行设计的。事件的触发,只能由事件的发行者负责,事件的订阅者只负责触发时执行什么动作。

2 用Reflector工具对上面的示例进行反编译,这句定义:public static event GreetingDelegate delegate1;其实变成了:

private static GreetingDelegate delegate1;//修饰符变为了private,这解释了为什么只能由事件的发行者负责触发调用

public static GreetingDelegate delegate1;//这里的Public修饰符才是我们写代码时给事件定义的修饰符。

{

    add{…}

    remove{…}

}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值