控件中国网现已改版,您看到的是老版本网站的镜像,系统正在为您跳转到新网站首页,请稍候.......
中国最专业的商业控件资讯网产品咨询电话:023-67870900 023-67871946
产品咨询EMAIL:SALES@COMPONENTCN.COM

委托与实践

作者:未知 出处:cnblog 2013年01月14日 阅读:

 委托的概念 

 
--------------------------------------------------------------------------------
 
一.定义:委托是一种封装方法的类型, 通过委托可以调用方法,相当于C/C++中函数指针的概念. 但不同的是,委托不光是一个函数地址, 而是一个面向对象的类型. 其中封装了指向对象的实例和方法。
 
二.要点:委托相对于其他类型来说相对抽象,因为其中有很多特殊的封装。
 
1.使用委托时,不能用delegate来定义一个实例,而必须先使用delegate来定义一个新的类型(真正使用的委托类型),这个类型提供了委托所需要指向的方法的模板.然后用这个自定义类型再申明实例使用。
2.委托的实例不仅封装了一个方法的引用,而且可以形成委托链,对聚合的多个方法进行链式调用。
3.FCL提供了多个已封装的常用委托类型,如Action, Func, EventHandler等,善于利用这些已封装的委托类型,特别是泛型委托,可以实现更好的设计。
4.委托虽然是封装方法调用的类型,但他可以作为其他方法的参数以及局部变量被调用,这也是一个较难理解的知识点。
5.委托有多种调用方式,在.NET 3.0之后的版本,可以使用Lambda表达式来编码较为简单的委托封装。
6.委托可以封装其他类型的实例方法,也可以封装静态方法。
 
三.代码示例
 
internal sealed class DelegateIntro {
   //申明一个委托类型;此类型的实例指向一个采用Int32参数,以及返回void的方法 
   internal delegate void Feedback(Int32 value);
 
   public static void Go() {
      StaticDelegateDemo();
      InstanceDelegateDemo();
      ChainDelegateDemo1(new DelegateIntro());
      ChainDelegateDemo2(new DelegateIntro());
   }
 
   /// <summary>
   /// 静态方法封装
   /// </summary>
   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)); // "Program." is optional
      Console.WriteLine();
   }
 
    /// <summary>
    /// 实例方法封装
    /// </summary>
   private static void InstanceDelegateDemo() {
      Console.WriteLine("----- Instance Delegate Demo -----");
      DelegateIntro di = new DelegateIntro();
      Counter(1, 3, new Feedback(di.FeedbackToFile));
 
      Console.WriteLine();
   }
 
    /// <summary>
    /// 委托链实例一
    /// </summary>
    /// <param name="di"></param>
   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);
   }
 
    /// <summary>
    /// 委托链示例2
    /// </summary>
    /// <param name="di"></param>
   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();
   }
}           
 
委托的使用
 
--------------------------------------------------------------------------------
 
一.委托的一般调用
 
1.使用场景:如上一节中的代码示例可作为委托链的一般调用案例。
2.使用顺序:
•定义委托类型。
•定义委托实例。
•封装引用方法。
•通过委托实例来调用封装方法。
 
二.委托链的一般调用
 
1.使用场景:如上一节中的代码示例可作为委托链的一般调用案例。
2.使用方法:
•定义委托类型。
•定义委托实例。
•封装多个引用方法或者从委托链中删除方法引用。
•通过委托实例来实现链式调用方法。
3.使用GetInvocationList()获取委托链的信息,示例如下:
 
nternal static class GetInvocationList {
   // Define a Light component.
   internal sealed class Light {
      // This method returns the light's status.
      public String SwitchPosition() {
         return "The light is off";
      }
   }
 
   // Define a Fan component.
   internal sealed class Fan {
      // This method returns the fan's status.
      public String Speed() {
         throw new InvalidOperationException("The fan broke due to overheating");
      }
   }
 
   // Define a Speaker component.
   internal sealed class Speaker {
      // This method returns the speaker's status.
      public String Volume() {
         return "The volume is loud";
      }
   }
 
   // Definition of delegate that allows querying a component's status.
   private delegate String GetStatus();
 
   public static void Go() {
      // Declare an empty delegate chain.
      GetStatus getStatus = null;
 
      // Construct the three components, and add their status methods 
      // to the delegate chain.
      getStatus += new GetStatus(new Light().SwitchPosition);
      getStatus += new GetStatus(new Fan().Speed);
      getStatus += new GetStatus(new Speaker().Volume);
 
      // Show consolidated status report reflecting 
      // the condition of the three components.
      Console.WriteLine(GetComponentStatusReport(getStatus));
   }
 
   // Method that queries several components and returns a status report
   private static String GetComponentStatusReport(GetStatus status) {
 
      // If the chain is empty, there is nothing to do.
      if (status == null) return null;
 
      // Use this to build the status report.
      StringBuilder report = new StringBuilder();
 
      // Get an array where each element is a delegate from the chain.
      //此处status是一个GetStatus委托的实例,封装了一个委托链
      Delegate[] arrayOfDelegates = status.GetInvocationList();
 
      // Iterate over each delegate in the array. 
      foreach (GetStatus getStatus in arrayOfDelegates) {
 
         try {
            // Get a component's status string, and append it to the report.
            report.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);
         }
         catch (InvalidOperationException e) {
            // Generate an error entry in the report for this component.
            Object component = getStatus.Target;
            report.AppendFormat(
               "Failed to get status from {1}{2}{0}   Error: {3}{0}{0}",
               Environment.NewLine,
               ((component == null) ? "" : component.GetType() + "."),
               getStatus.Method.Name, e.Message);
         }
      }
 
      // Return the consolidated report to the caller.
      return report.ToString();
   }
 
三.异步调用委托
 
1.通过delegate封装的委托类型所派生的实例会自动生成Invoke(), BeginInvoke(), EndInvoke()方法,由此可见可以异步的调用委托。
2.异步调用委托的使用顺序是:
•定义委托类型。
•定义委托实例。
•封装委托方法。
•使用BeginInvoke()异步调用委托方法,并指定一个AsyncCallback委托类型的实例方法,例如Callback(),作为异步操作的回调操作方法。
•在Callback()中根据BeginInvoke()执行的结果(作为IAsyncResult类型的参数传入),在Callback()中调用EndInvoke()方法。
3.实现异步调用委托的同时,需要跟其他系统委托类型打交道,也增加了理解难度,请注意。
4.接下来,我们省略定义委托类型这一步,使用一个Action委托(可以理解为一个自定义委托类型)来演示异步调用委托。
 
class Program
    {
        static void Main(string[] args)
        {
            //Action委托的异步委托
            Action<int> action = Speak;
            AsyncCallback callback=new AsyncCallback(CallBackMethod);
            action.BeginInvoke(10, callback, action);
            Console.WriteLine("当前线程ID:{0}", Thread.CurrentThread.ManagedThreadId.ToString());
 
            Console.ReadKey();
           
        }
 
 
        //回调方法
        static void CallBackMethod(IAsyncResult ar)
        {
            
            Action<int> a = (Action<int>)ar.AsyncState;
            a.EndInvoke(ar);
        }
 
 
        //被委托方法
        static void Speak(int i)
        {
            string str = string.Format("The number is {0}",i);
            Console.WriteLine("当前线程ID:{0}",Thread.CurrentThread.ManagedThreadId.ToString());
            Thread.Sleep(TimeSpan.FromSeconds(3));
            Console.WriteLine(str);
        }
    } 
 
委托实践
 
--------------------------------------------------------------------------------
 
一.在实践中常用的FCL中已定义的委托类型
 
1.EventHandler:FCL中各种前端控件中的事件,基本都用这个委托类型封装。我们在编码中的自定义事件,如果没有特殊的传递需求(EventArgs),也可以直接使用这个委托类型。
2.Action<T>:此委托类型适用于各种不需要返回数据的方法类型封装,支持泛型,最多支持十六个输入参数。
3.Func<in T1, out T2):此委托类型适用于各种需要返回数据的方法类型封装,但不支持带有ref, out修饰符参数的方法封装。
4.各种CallBack回调函数封装:例如AsyncCallback,WaitCallback等。
5.其他封装:例如用于查询的Predicate<T>, 用于转换的Converter<T1,T2>, 用于比较的Comparison<T>等。
 
 
二.使用Lambda表达式
 
1.Lambda表达式可以理解成为是一种对匿名方法的封装,这个主要在后面的进阶特性中讲。
2.因为委托是对方法和方法组的封装,所以委托封装的对象自然可以用Lambda表达式来编写,这个在一些使用委托作为参数的方法中常用。
3.列举几个数组Array中的方法和线程池中的异步方法调用作为示例:
 
internal static class AnonymousMethods {
   public static void Go() {
      // Create and initialize a String array
      String[] names = { "Jeff", "Kristin", "Aidan" }; 
 
      // Get just the names that have a lowercase 'i' in them.
      Char charToFind = 'i'; 
      names = Array.FindAll(names, delegate(String name) { return (name.IndexOf(charToFind) >= 0); });
       
      // Convert each string's characters to uppercase
      names = Array.ConvertAll<String, String>(names, delegate(String name) { return name.ToUpper(); });
      
      // Sort the names 
      Array.Sort(names, delegate(String name1, String name2) { return String.Compare(name1, name2);});
 
      Array.Sort(names, (x1, x2) => { x1 = "1"; return string.Compare(x1, x2); }); 
 
      // Display the results 
      Array.ForEach(names, delegate(String name) { Console.WriteLine(name); }); 
   }
 
   private sealed class AClass {
      private static void CallbackWithoutNewingADelegateObject() {
         ThreadPool.QueueUserWorkItem(delegate(Object obj) { Console.WriteLine(obj); }, 5);
      }
   }
 
   private sealed class AClass2 {
      private static void UsingLocalVariablesInTheCallbackCode(Int32 numToDo) {
 
         // Some local variables
         Int32[] squares = new Int32[numToDo];
         AutoResetEvent done = new AutoResetEvent(false);
 
         // Do a bunch of tasks on other threads
         for (Int32 n = 0; n < squares.Length; n++) {
            ThreadPool.QueueUserWorkItem(
               delegate(Object obj) {
                  Int32 num = (Int32)obj;
 
                  // This task would normally more time consuming
                  squares[num] = num * num;
 
                  // If last task, let main thread continue running
                  if (Interlocked.Decrement(ref numToDo) == 0)
                     done.Set();
               }, n);
         }
 
         // Wait for all the other threads to finish
         done.WaitOne();
 
         // Show the results
         for (Int32 n = 0; n < squares.Length; n++)
            Console.WriteLine("Index {0}, Square={1}", n, squares[n]);
      }
   }
}

热推产品

  • ActiveReport... 强大的.NET报表设计、浏览、打印、转换控件,可以同时用于WindowsForms谀坔攀戀Forms平台下......
  • AnyChart AnyChart使你可以创建出绚丽的交互式的Flash和HTML5的图表和仪表控件。可以用于仪表盘的创......
首页 | 新闻中心 | 产品中心 | 技术文档 | 友情连接 | 关于磐岩 | 技术支持中心 | 联系我们 | 帮助中心 Copyright-2006 ComponentCN.com all rights reserved.重庆磐岩科技有限公司(控件中国网) 版权所有 电话:023 - 67870900 传真:023 - 67870270 产品咨询:sales@componentcn.com 渝ICP备12000264号 法律顾问:元炳律师事务所 重庆市江北区塔坪36号维丰创意绿苑A座28-5 邮编:400020
在线客服
在线客服系统
在线客服
在线客服系统