Spiga

delegate详细解析

2011-05-06 05:32 by 梁逸晨, 165 visits, 收藏, 编辑

Delegate实际上是一个类型(class)。这一点我们可以做一个实验例子。

 

using System;

 

delegate void Print(string message);

 

sealed  class Testing

{

    public static void Execute(Print p)

    {

        p("testing");

    }

}

 

sealed class Program

{

    static void prt(string str){ Console.WriteLine(str);  }

 

    static void Main(string[] args)

    {

        Testing.Execute(prt);

    }

}

 

 

然后我们通过IL代码观察:

 

代理,也就是delegate Print  实际上是一个sealed class ,见 特征1 ,继承于System.MulticastDelegate

 

特征2 更明显,直接说明了Print就是一个class

 

构造函数和两个多线程方法我们暂且不谈, 这里的重点是它具备一个Invoke 方法, 类型是void, 签名类型是string

 

我们用两个方法来试探一下这个Invoke是什么, 首先,我们通过代码调用顺序,查找一下Testing 类的静态方法  Execute(Print p) 做了些什么:

 

 

 

实际上调用了Print对象的Invoke 方法,参数就是之前压入栈的“string”。 这下我们明白了, Invoke方法就是我们定义的  delegate void Print(string message); 的真身。  

 

再来一个方法证实一下这个猜测,我们修改一下C#源代码:

 

using System;

 

delegate void Print(string message);

 

delegate void Dele2(int i, DateTime d); //增加一个新的代理

 

sealed  class Testing

{

    public static void Execute(Print p , Dele2 d)

    {

        p("testing");

        d(10, DateTime.Now);

    }

}

 

 

sealed class Program

{

    static void prt(string str){ Console.WriteLine(str);  }

   

    static void ptr2(int i, DateTime d)

    {

        Console.WriteLine(string.Format("{0},{1}",i,d));

    }

 

    static void Main(string[] args)

    {

        Testing.Execute(prt,ptr2);

    }

}

 

然后我们再来看看生成IL代码:

 

 

 

 

这下勿须置疑了,我们可以这样子认为:

 

Delegate 实际上就是一个特殊的类型,只不过是我们的声明的时候可以简化写法,系统实际上还是会编译为sealed class , 这个特殊的类中,会使用一个拥有相同签名的方法来实际执行

 

最后,做一次验证,我们再修改一下代码:

 

using System;

 

delegate void Print(string message);

 

delegate void Dele2(int i, DateTime d);

 

sealed  class Testing

{

    public static void Execute(Print p , Dele2 d)

    {

        p.Invoke("testing"); //改动点

 

        d.Invoke(10, DateTime.Now); //改动点

 

        //我们直接调用它们的Invoke方法

    }

}

 

 

sealed class Program

{

    static void prt(string str){ Console.WriteLine(str);  }

   

    static void ptr2(int i, DateTime d)

    {

        Console.WriteLine(string.Format("{0},{1}",i,d));

    }

 

    static void Main(string[] args)

    {

        Testing.Execute(prt,ptr2);

    }

}

成功执行: