笔记:委托、事件(不完全)

委托:
delegate void StringProcessor(string input); // 定义委托
 
    class Program
    {
        static void Main(string[] args)
        {
            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."); // C#简化写法
            tomsVoice.Invoke("Hello, Daddy"); // 委托调用本质,Invoke方法(还负责遍历委托链)
            background("An airplane files past.");
 
            Console.ReadKey();
        }
    }
 
    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);
        }
    }



委托是一个类,它定义了方法的原型(返回类型和一组参数),类似包含单一方法的接口,使得可以将方法当作另一个方法的参数来进行传递。
委托对象(实例)是方法的一个包装器(wrapper),使方法能通过包装器来间接回调

delegate   void   StringProcessor ( string  input);

这行代码编译后,编译器会这样定义一个完整的类:



该类派生自FCL中定义的System.MulticastDelegate(所有委托类型都派生自该类,该类派生自Delegate,Delegate有Combine和Remove两个方法)

MulticastDelegate三个关键字段:
System.Object _target;(委托对象包装静态方法时,为null;包装实例方法时,引用的是回调方法要操作的对象)
System.IntPtr _methodPtr;(标识要回调的方法)
System.Object _invocationList;(通常为null,构造一个委托链时,引用一个委托数组)

每个委托实例都可构造一个委托链:
使用Delegate.Combine和Delegate.Remove两个静态方法可以动态添加、移除委托, C#重载了+=和-=操作符分别对应它们

每次添加、移除委托,返回的都是另外一个新委托(已添加或删除,因为_invocationList指向的是一个委托数组,需要新建一个新大小的委托数组)。

如果委托是带返回值的,当调用委托时,返回的是委托链最后一个委托的返回值。

将一个方法绑定到委托时,C#和CLR都允许引用类型的协变性和逆变性(只能用于引用类型,不能用于值类型或void)。
协变性:是指方法能返回从委托的返回类型派生的一个类型。
逆变性:指方法获取的参数可以是委托的参数类型的及类型。
例:
     delegate object MyCallback(FileStream s);
可以构造该委托类型的一个实例,并和具有以下原型的一个方法绑定:
     string SomeMethod(Stream s);

泛型委托:
无返回值:Action
有返回值:Func

事件:
事件的基础是委托,在声明为事件时,不管是不是public(一般都声明为public,不然外部怎么访问),编译过后都会变为private的委托字段(去掉声明事件时的event关键字)。然后暴露访问权限为public的“事件属性”(自己取的名),里面有add访问符和remove访问符,类似属性的getset访问符。在add访问符中使用Delegate.Combine构造委托链,在remove访问符中使用Delegate.Remove从委托链中移除一个委托。

“事件”类似“属性”,两者都声明为具有一种特定的类型。对于事件来说,该类型必须是一个委托类型。
使用属性时,感觉就像是直接对它的字段进行取值和赋值,但实际是在使用“get_属性名”和“set_属性名”访问器方法。
使用事件时,看起来就像是在通过+=和-=操作符使用委托类型的字段,但实际实在调用“add_事件名”和“remove_事件名”访问器方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值