zoukankan      html  css  js  c++  java
  • 委托和事件

    回调(call back)函数是windows编程的一个重要部分,回调函数实际上就是方法调用的指针,也称为函数指针,是一个非常强大的编程特性。在.NET中以委托的形式实现了函数指针的概念,委托是类型安全的。本文主要描述C#中委托和事件的原理和实现。

    一、委托

    1.1 在C#中使用委托

    在C#中,最好将委托看作是对象的一种新类型。使用委托和类一样,需要先定义,然后实例化。定义委托的语法如下:
    delegate void VoidPreration(uint x);
    这里定义了一个委托VoidPreration,并指定该委托的每个实例都包含一个方法的细节,该方法带有一个uint参数,并返回void。委托的类型安全性非常重要,定义委托时,必须给出它所代表的方法的全部细节。
    委托的实例化语法如下:
    public void SomeMethod(uint x)
    {
      
    //.
    }

    static void Main()
    {  
      VoidPreration voidPreration 
    = new VoidPreration(SomeMethod);//实例化委托
      voidPreration();//委托实例的调用
    }

    注意:给定委托的实例时,可以表示任何类型的任何对象上的实例方法或静态方法——只要方法的特征匹配于委托的特征即可。

    1.2 委托实例

    下面给出两个使用委托的实例
    //在这个示例中,定义一个类MathsOperation,它有两个静态方法,对double类型的值执行两个操作,然后使用该委托调用这些方法。
    using System;
    namespace SimepleDelegate
    {
      
    //类 MathsOperations 
      public class MathsOperations
      
    {
        
    public static double MultiplyByTwo(double value)
        
    {
          
    return value*2;
        }

        
    public static double Square(double value)
        
    {
          
    return value*value;
        }

      }


      
    //定义委托
      delegate double DoubleOp(double x);
      
    //测试
      public class MainEntryPoint
      
    {
        
    static void Main()
        
    {
          DoubleOp[] operations 
    = 
              
    {
                 
    new DoubleOp(MathsOperations.MultiplyByTwo),
                 
    new DoubleOp(MathsOperations.Square)
              }

          
    private void ProcessAndDisplayNumber(DoubleOp action, double value)
          
    {
            
    double result = action(value);
            ConsoleWriteLine(
    "value is {0}, result of operation is {1}",value,result);
          }

          
    for(int i = 0; i<operations.Length; i++)
          
    {
            Console.WriteLine(
    "using operation[{0}]:",i);
            ProcessAndDisplayNumber(operation[i],
    2.0);
            Console.WriteLine();
          }

        }

      }

    }

    结果为:
    using operations[0]:
    value 
    is 2,result of operation is 4

    using operation[1];
    value 
    is 2,result of operation is 4

    //BubbleSorter示例
    //类BubbleSorter执行一个静态方法Sort(),这个方法的第一个参数时一个对象数组,把该数组按照升序重新排列。
    //由于排序的数组可以是任意对象,所以这里需要定义一个委托
    delegate bool CompareOp(object lhs, object rhs);
    //类BubbleSorter
    public class BubbleSorter
    {
      
    public static void Sort(object[] sortArray, CompareOp gtMethod)
      
    {
        
    for(int i = 0; i<sortArray.Length; i++)
        
    {
          
    for(int j = i+1; j<sortArray.Length;j++)
          
    {
            
    if(gtMethos(object[j],object[i]))
            
    {
              
    object temp = object[i];
              
    object[i] = object[j];
              
    object[j] = temp;
            }

          }

        }

      }

    }


    //定义Employee类,建立要排序的数组
    public class Employee
    {
      
    private string name;
      
    private decimal salary;
      
    public Employee(string name, decimal salary)
      
    {
        
    this.name =  name;
        
    this.salary = salary;
      }

      
    public override string ToString()
      
    {
        
    return string.Format(name + ", {0,C}",salary);
      }

      
    //比较大小的方法
      public static bool RhsIsGreater(object lhs, object rhs)
      
    {
        Employee empLhs 
    = (Employee)lhs;
        Employee empRhs 
    = (Employee)rhs;
        
    return (empRhs.salary >empLhs.salary)? true:false;
      }

    }


    //测试
    public class MainEntryPoint
    {
      Employee[] employees 
    = 
           
    {
             
    new Employee("wang",2000),
             
    new Employee("chen",1000),
             
    new Employee("zhu",3000),
             
    new Employee("li",2500)
           }
    ;
      CompareOp employeeCompareOp 
    = new CompareOp(Employee.RhsIsGreater);//实例化委托
      BubbleSorter.Sort(employees,employeeCompareOp);//委托调用
      for(int i = 0; i<employees.Length; i++)
      
    {
        Console.WriteLine(employees[i].ToString());
      }

    }


    //运行结果

    chen, $
    1,000.00
    wang, $
    2,000.00
    li, $
    2,500.00
    zhu, $
    3,000.00

    1.3 多播委托

    前面介绍的委托都只包含一个方法调用,实际上委托可以包含多个方法,包含多个方法的委托叫做多播委托。如果调用多播委托,就可以按照顺序连续调用多个方法。为此多播委托的返回值必须是void(否则,返回值送到何处?)实际上,如果编译器发现某个委托返回void,就会自动假定这是一个多播委托。
    delegate void DoubleOp(double value);
    class MainEntryPoint
    {
      
    static void Main()
      
    {
        DoubleOp operations 
    = new DoubleOp(MathOperations.MultiplyByTwo);
        operation 
    += new DoubleOp(MathOperations.Square);
        
      }

    }

    //上面的多播委托等价于下面的代码
    DoubleOp operation1 = new DoubleOp(MathOperations.MultiplyByTwo);
    DoubleOp operation2 
    = new DoubleOp(MathOperations.Square);
    DoubleOp operations 
    = operation1 + operation2;
    注意:如果使用多播委托,就应注意对同一个委托调用方法链的顺序并未正式定义,因此应避免编写依赖于任意特定顺序调用方法的代码。

    二、事件

    在开发基于对象的应用程序时,对象之间需要通信,例如在一个对象中发生了什么有趣的事情时,需要通知其它对象发生了什么变化,这里就需要用到事件。可以把事件作为对象之间通信的介质。而委托就用作应用程序接收到消息时封装事件的方式。
    下面通过一个例子来说明C#中事件的创建、引发、接收和取消事件。

    //这个例子包含一个窗体,它会引发另一个类正在监听的事件。在引发事件后,接收对象就确定是否执行一个过程,如果该过程未能继续,就取消事件。
    //用于生成事件的窗口包含一个按钮和一个标签
    namespace EventTest
    {
        
    public  partial class Form1 : Form
        
    {
            
    public delegate void ActionEventHandler(object sender, ActionCancelEventArgs ev);
            
    public static event ActionEventHandler Action;
            
    public BusEntity busEntity = new BusEntity();
            
    public Form1()
            
    {
                InitializeComponent();            
                
            }


            
    private void OnAction(object sender, ActionCancelEventArgs ev)
            
    {
                
    if (Action != null)
                
    {
                    Action(sender, ev);
                }

            }


            
    private void button1_Click(object sender, EventArgs e)
            
    {
                ActionCancelEventArgs cancelEvent 
    = new ActionCancelEventArgs();
                OnAction(
    this, cancelEvent);
                
    if (cancelEvent.Cancel)
                
    {
                    
    this.label1.Text = cancelEvent.Message;
                }

                
    else
                
    {
                    
    this.label1.Text = this.busEntity.TimeString;
                }

            }


        }

        
    public class ActionCancelEventArgs : System.ComponentModel.CancelEventArgs
        
    {
            
    string msg = "";
            
    public ActionCancelEventArgs() :base(){}
            
    public ActionCancelEventArgs(bool cancel) : base(cancel) { }
            
    public ActionCancelEventArgs(bool cancel, string message)
                : 
    base(cancel)
            
    {
                
    this.msg = message;
            }


            
    public string Message
            
    {
                
    get return this.msg;}
                
    set {this.msg = value;}
            }

            
        }


        
    //事件接收器
        public class BusEntity
        
    {
            
    string time = "";
            
    public BusEntity()
            
    {
                Form1.Action 
    += new Form1.ActionEventHandler(Form1_Action);
            }


            
    private void Form1_Action(object sender, ActionCancelEventArgs ev)
            
    {
                ev.Cancel 
    = !DoAction();
                
    if (ev.Cancel)
                
    {
                    ev.Message 
    = "Wasn't the right time";
                }

            }

            
    private bool DoAction()
            
    {
                
    bool retVal = false;
                DateTime tm 
    = DateTime.Now;
                
    if (tm.Second < 30)
                
    {
                    
    this.time = "The time is " + DateTime.Now.ToLongTimeString();
                    retVal 
    = true;
                }

                
    else
                
    {
                    
    this.time = "";                
                }

                
    return retVal;
            }

            
    public string TimeString
            
    {
                
    get return this.time; }
            }

        }


    }

  • 相关阅读:
    模块化编程
    flex 弹性布局
    作用域与作用域链
    深入解读JavaScript面向对象编程实践
    javascript Null、Undefined 、NaN的联系与区别
    跨域常见解决方案
    Reverse Pairs
    315. Count of Smaller Numbers After Self
    2. Add Two Numbers
    657. Judge Route Circle
  • 原文地址:https://www.cnblogs.com/justnow/p/636951.html
Copyright © 2011-2022 走看看