深入理解C#(七)

*第二章(C# 1的核心基础)

委托,类型系统的特征,值/引用类型

委托(delegate)

  1. 类似于C语言的函数指针
  2. 不指定一个要执行的行为,将这个行为用某种方式“包含在一个对象中”

1. 委托的构成

  • 声明委托类型

  • 必须有一个方法包含了要执行的代码

  • 必须创建一个委托实例

  • 必须调用invoke委托实例

    namespace Chapter02
    ​ {
    ​ //声明委托类型
    ​ delegate void StringProcessor(string input);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    class Person
    {
    string name;

    public Person(string name)
    {
    this.name = name;
    }

    //声明兼容的实例方法
    public void Say(string message)
    {
    Console.WriteLine("{0} says: {1}", name, message);
    }
    }

    class Background
    {
    //声明兼容发静态方法
    public static void Note(string note)
    {
    Console.WriteLine("({0})", note);
    }
    }

    [Description("Listing 2.1")]
    class SimpleDelegateUse
    {
    static void Main()
    {
    Person jon = new Person("Jon");
    Person tom = new Person("Tom");
    //创建三个委托实例
    StringProcessor jonsVoice, tomsVoice, background;
    jonsVoice = new StringProcessor(jon.Say);
    tomsVoice = new StringProcessor(tom.Say);
    background = new StringProcessor(Background.Note);
    //调用委托实例
    jonsVoice("Hello, son.");
    tomsVoice.Invoke("Hello, Daddy!");
    background("An airplane flies past.");
    }
    }

    }

    具体步骤:

  1. 声明一个委托类型。
  2. 找到或写一个方法,具有和委托类型相同的签名,并能做我们想做的事情。
  3. 创建委托实例,指定在调用委托实例时,执行该方法。(创建委托实例,取决于操作使用实例方法还是静态方法。具体做法就是new一个我们声明的委托类型,把任意匹配的方法,作为参数传入)
  4. 调用委托实例,可以显示用Invoke方法调用,也可用简化语句直接调用。

类比:委托就像提前请律师打官司,声明委托类型就像指明要处理那种类型的案件,找到或写一个方法就像找到一个满足要求的律师,创建委托实例就像和律师签订协议,在需要时调用委托实例,就像遇上官司了,就要请律师出门解决。所以实际执行的方法是律师在做,委托只是提前签好协定,这样我们就可以在任何有需求的时候解决问题。

合并和删除委托

实际使用时,委托实例往往有一个操作列表(invocation list)与之关联。Combine负责将两个委托实例的调用列表连接到一起,Remove负责从一个委托实例中删除另一个实例的调用列表。一般使用+和+=操作符代替Combine。

注意: 委托和string一样是不易变的。Combine和String.Concat很像,合并现有实例来形成新的实例。

可用-和-=简写Remove操作

注意:若委托的签名有一个非void的返回类型,则Invoke的返回值是最后一个操作的返回值。除非使用GetInvocationList获取操作列表时,都显示调用某个委托,否则只能看到最后一个操作的返回值。

注意:如果调用列表中断任何操作爆出一个异常,都会组织执行后续操作。

事件的简单讨论

基本思想:让代码在发生某事时作出响应。

注意:事件不是委托类型的字段,但C#允许使用字段风格的时间(field-like event)

可以将事件看作类似属性的东西。两者都声明具有一种特定的类型,对于事件来说,是一个委托类型。(即:事件之于委托,就像属性之于字段)使用属性,实际是在调用方法。实现属性,可在方法中添加别的功能(校验机制之类)。同样订阅或取消订阅事件,实际是在调用(add和remove方法)

既然能用委托实现为什么还要事件?

和属性类似,事件添加了一个封装层,实现发布/订阅模式。Delegates and Events

字段风格的事件,只需要一个声明。编译器将声明转换成一个具有默认add/remove实现的事件和一个私有委托类型的字段。表面上调用一个事件,实际调用存储在字段中的委托实例。