• CLR VIA C#委托


    1.什么是委托?委托就是一种回调函数的机制,将函数作为一个参数传递给其他对象,当该对象需要的时候调用委托来达到回调函数的目的。

    通俗点的说法是:你将一件事情交给别人去做。例如你QQ里的自动回复,为了第一时间回复别人,你不可能一直守在QQ面前一有消息通知你就回复。所以你只好定义一个回复的方法,将这个方法交给QQ,告诉QQ当有消息过来的时候就调用你这个方法。QQ会给你这个方法传一个参数"对不起,我现在很忙balabala...",然后自动回复给对方

    ==========================================================我是解释的分割=========================================================

    其实这里有两种情况,单就翻译而言,我觉得上面的解释比较符合“委托”的意思,就是你让别人帮你做你应该去做的事。而事件是一种特殊的委托,是别人通知你该做某事了,而做事的人还是你自己。实际委托是一个类型,把一个方法传递给委托会新创建一个对象,这个对象对方法进行包装。所以不管是哪种情况,都是委托对象调用方法。

    =============================================================================================================================

    2.其实委托很早就有了,说白了他只是函数指针在C#中的实现而已,不过在C#里他是类型安全的,并且可以顺序调用多个委托,支持静态方法和实例方法的调用。

    3.正所谓无图无真相,没代码说JB,下面来看下委托实现的简单代码(以下代码来自CLRVIAC#)

    using System;
    using System.Linq;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using System.Reflection;
    public sealed class Program {
       public static void Main() {
          DelegateIntro.Go();
       }
    }
    internal sealed class DelegateIntro {
       // 申明一个委托类型,他的实例(既然委托是一个类型,那么他其实会创建一个实例)引用一个方法,该方法接收一个Int32型的参数,返回空值
       internal delegate void Feedback(Int32 value);
    
       public static void Go() {
          StaticDelegateDemo();
       }
    
       private static void StaticDelegateDemo() {
          Console.WriteLine("----- Static Delegate Demo -----");
          Counter(1, 3, null);
          Counter(1, 3, new Feedback(DelegateIntro.FeedbackToConsole));
          Counter(1, 3, new Feedback(FeedbackToMsgBox)); 
          Console.WriteLine();
       }
       private static void Counter(Int32 from, Int32 to, Feedback fb) {
          for (Int32 val = from; val <= to; val++) {
             if (fb != null)
                fb(val);
          }
       }
       private static void FeedbackToConsole(Int32 value) {
          Console.WriteLine("Item=" + value);
       }
       private static void FeedbackToMsgBox(Int32 value) {
          MessageBox.Show("Item=" + value);
       }
    }

    以上是委托调用静态方法的例子,记住Counter这个函数接收3个参数,将遍历从from到to的值,并将它传递给FeedBack这个委托对象fb饮用的方法,然后调用该方法。

    正如前面所说,这里创建了一个委托对象Feedback的一个实例

    new Feedback(DelegateIntro.FeedbackToConsole)

    ,这个实例通过构造器传入的参数(方法签名)对方法进行了包装。然后将这个实例传入Counter函数中。需要注意的是这个委托实例包装的是一个静态方法,所以实例的内部并没有对其他对象的引用。

    委托调用实例方法的例子如下

    using System;
    using System.Linq;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using System.Reflection;
    
    public sealed class Program {
       public static void Main() {
          DelegateIntro.Go();
       }
    }
    internal sealed class DelegateIntro { // 申明一个委托类型,他的实例(既然委托是一个类型,那么他其实会创建一个实例)引用一个方法,该方法接收一个Int32型的参数,返回空值 internal delegate void Feedback(Int32 value); public static void Go() { InstanceDelegateDemo(); } private static void InstanceDelegateDemo() { Console.WriteLine("----- Instance Delegate Demo -----"); DelegateIntro di = new DelegateIntro(); Counter(1, 3, new Feedback(di.FeedbackToFile)); } private static void Counter(Int32 from, Int32 to, Feedback fb) { for (Int32 val = from; val <= to; val++) { // If any callbacks are specified, call them if (fb != null) fb(val); } } private void FeedbackToFile(Int32 value) { StreamWriter sw = new StreamWriter("Status", true); sw.WriteLine("Item=" + value); sw.Close(); } }

    这里委托对象封装的是一个实例方法,所以内部会持有这个实例的一个引用,这个应用可以通过委托对象的target属性获得。

    创建一个委托链的方式如下

    using System;
    using System.Linq;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using System.Reflection;
    
    public sealed class Program {
       public static void Main() {
          DelegateIntro.Go();
       }
    }
    
    
    internal sealed class DelegateIntro {
       // 申明一个委托类型,他的实例(既然委托是一个类型,那么他其实会创建一个实例)引用一个方法,该方法接收一个Int32型的参数,返回空值
       internal delegate void Feedback(Int32 value);
    
       public static void Go() {
          ChainDelegateDemo1(new DelegateIntro());
          ChainDelegateDemo2(new DelegateIntro());
       }
    
    
       private static void ChainDelegateDemo1(DelegateIntro di) {
          Console.WriteLine("----- Chain Delegate Demo 1 -----");
          Feedback fb1 = new Feedback(FeedbackToConsole);
          Feedback fb2 = new Feedback(FeedbackToMsgBox);
          Feedback fb3 = new Feedback(di.FeedbackToFile);
    
          Feedback fbChain = null;
          fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
          fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
          fbChain = (Feedback)Delegate.Combine(fbChain, fb3);
          Counter(1, 2, fbChain);
    
          Console.WriteLine();
          fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
          Counter(1, 2, fbChain);
       }
    
       private static void ChainDelegateDemo2(DelegateIntro di) {
          Console.WriteLine("----- Chain Delegate Demo 2 -----");
          Feedback fb1 = new Feedback(FeedbackToConsole);
          Feedback fb2 = new Feedback(FeedbackToMsgBox);
          Feedback fb3 = new Feedback(di.FeedbackToFile);
    
          Feedback fbChain = null;
          fbChain += fb1;
          fbChain += fb2;
          fbChain += fb3;
          Counter(1, 2, fbChain);
    
          Console.WriteLine();
          fbChain -= new Feedback(FeedbackToMsgBox);
          Counter(1, 2, fbChain);
       }
    
       private static void Counter(Int32 from, Int32 to, Feedback fb) {
          for (Int32 val = from; val <= to; val++) {
             // If any callbacks are specified, call them
             if (fb != null)
                fb(val);
          }
       }
    
       private static void FeedbackToConsole(Int32 value) {
          Console.WriteLine("Item=" + value);
       }
    
       private static void FeedbackToMsgBox(Int32 value) {
          MessageBox.Show("Item=" + value);
       }
    
       private void FeedbackToFile(Int32 value) {
          StreamWriter sw = new StreamWriter("Status", true);
          sw.WriteLine("Item=" + value);
          sw.Close();
       }
    }

    我们看到ChainDelegateDemo1里使用了Delegate.Combine这个静态方法来创建一个委托链,而ChainDelegateDemo2使用的是+=这个运算符的重载。

    实际上CLR内部的情况正如ChainDelegateDemo1所示,调用了Delegate.Combine来创建委托链。+=号只是C#编译器提供的语法糖而已。

    相似的,我们也可以使用Delegate.Remove或者-=来从委托链中移除一个委托。

    4.委托和观察者模式。

    首先看看观察者模式的定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[GOF 《设计模式》]

    重点在于:

    当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知

    所以这种模式中会有两个对象存在:观察者(订阅者),通知者(发布者)

    观察者希望发布者通知他何时去更新,发布者希望能够增加或者减少发布者的数量并且通知观察者。简单的代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication4
    {
        //定义一个通知者类,当需要更新的时候通知观察者进行更新
        class NotifyClass
        {
            public delegate void Update(NotifyClass nc);
            public Update UpdateEvent;
            public Int32 i_Update;
            public void Notify() 
            {
                if (UpdateEvent != null)
                {
                    UpdateEvent(this);
                }
            }
        }
        //OB1类中只有一个方法监听通知类的通知事件
        class Observer1
        {
            public void Ob1NotifiedUpdate(NotifyClass nc) 
            {
                Console.WriteLine(nc.i_Update);
            }
        }
        class Observer2
        {
            public void Ob2NotifiedUpdate(NotifyClass nc)
            {
                Console.WriteLine(nc.i_Update+" from ob2");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                NotifyClass a = new NotifyClass();
                a.UpdateEvent += (new Observer1().Ob1NotifiedUpdate);
                a.UpdateEvent += (new Observer2().Ob2NotifiedUpdate);
           a.i_Update=100;  a.Notify(); Console.Read(); } } }

    我们可以知道,观察者模式的情况其实是发布者通知观察者需要更新,然后观察者去更新。但是正如我之前说的,使用委托的实际情况是委托对象将方法包装起来,然后由委托对象去调用包装起来的方法。并不是由观察者去调用的。或者我们可以理解为真正监听发布者的不是观察者,而是通过观察者方法构建的委托对象。

    所以我觉得下面的实现方式更加符合观察者模式

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication4
    {
        //定义一个通知者类,当需要更新的时候通知观察者进行更新
        class NotifyClass
        {
            public interface IUpdate 
            {
                void Updated(NotifyClass nc); 
            }
            public List<IUpdate> UpdateEvent=new List<IUpdate>();
            public Int32 i_Update;
            public void Notify() 
            {
                if (UpdateEvent != null)
                {
                    foreach (IUpdate iu in UpdateEvent)
                    {
                        iu.Updated(this);
                    }
                }
            }
            public void AddListener(IUpdate iu) 
            {
                UpdateEvent.Add(iu);
            }
            public void RemoveListener(IUpdate iu)
            {
                UpdateEvent.Remove(iu);
            }
        }
        //OB1类中只有一个方法监听通知类的通知事件
        class Observer1:NotifyClass.IUpdate
        {public void Updated(NotifyClass nc) 
            {
                Console.WriteLine(nc.i_Update);
            }
        }
        class Observer2:NotifyClass.IUpdate
        {
            public void Updated(NotifyClass nc)
            {
                Console.WriteLine(nc.i_Update+" from ob2");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                NotifyClass a = new NotifyClass();
                Observer1 ob1 = new Observer1();
                a.AddListener(ob1);
                a.i_Update = 100;
                a.Notify();
                Console.Read();
            }
        }
    }
  • 相关阅读:
    write to logfile
    open and read a file content to a variable
    strategy
    Android 开机启动程序
    消息队列
    卡机音乐功能实现
    Android 2.0 开机动画文件分析
    多线程实例
    消息队列
    多线程实例
  • 原文地址:https://www.cnblogs.com/iiaijimaai/p/3296167.html
Copyright © 2020-2023  润新知