ASP.NET深入浅出系列4- 也谈委托和事件

这个话题已经很多人谈过了,本不想重复拿出来说,但为了这个系列的完整性,我便把自己以前积累的东西整理了一下,大家全当消遣了。

作者:方明

一、委托的定义:
《高级汉语大词典》中是如下解释的:托付给别的人或机构办理。要说生活中的意思其实大家都能理解,无非是“当某人(机构)需要完成一件自己不能或不应该完成的事情的时候,此人(机构)物色一个合适的且有能力完成此事的人选,然后提供必要的信息,将此事委托给物色到的人(机构)来完成。” C#中的委托是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用可以像其他任何方法一样具有参数和返回值。委托对象能被传递给调用该方法引用的代码而无须知道哪个方法将在编译时被调用。委托是函数的封装,它代表一“类”函数。他们都符合一定的签名:拥有相同的参数列表、返回值类型。同时委托也可以看作是对函数的抽象,是函数的“类”。此时,委托实例代表一个具体的函数。委托应该和类同属一个层面,使用起来也很象一个类。我们先来看一个委托使用的实例:

ContractedBlock.gif ExpandedBlockStart.gif Code
public delegate void PrintHandler(string str);    // 声明委托类型

    
public class PrintStr
    {               
        
public void CallPrint(string input)
        {
            Console.WriteLine(input);
        }
        
    }
static void Main(string[] args)
{
            PrintStr myPrinter 
= new PrintStr();
            PrintHandler myHandler 
= null;
            
// 将委托链接到方法,来实例化委托
            myHandler += new PrintHandler(myPrinter.CallPrint); 

            
if (myHandler != null)
                myHandler(
"Hello World!");    // 调用委托,相当于匿名调用委托所链接的方法
            myHandler -= new PrintHandler(myPrinter.CallPrint);
            
if (myHandler == null)
                Console.WriteLine(
"myHandler==null");
            Console.Read();
}

 

得到的结果为
Hello World!
myHandler==null

 

二、委托的特点
1、一个委托对象可以搭载多个方法。
2、一个委托对象搭载的方法并不需要属于同一个类,但所搭载的方法必须具有相同的原形和形式。
3、委托的实例将代表一个具体的函数

 

三、为什么要使用委托
1、更加灵活的方法调用。我们先举一个例子:

ContractedBlock.gif ExpandedBlockStart.gif Code
namespace delegateEvent
{
  
public class BackupUtil
  {
    
string _buFolder = "c:\\backup\\";
    
    
//declare the delegate type
    public delegate bool BackupFiles(string folder);

    
public BackupFiles Backup;

    
public BackupUtil(string backupType)
    {
      
switch (backupType)
      {
        
case "EXE"  :
          Backup 
= new BackupFiles(BackupOnlyEXE);
          
break;
        
case "Folder" :
          Backup 
= new BackupFiles(BackupCurrentFolder);
          
break;
        
case "Today"  :
          Backup 
= new BackupFiles(BackupAccessedToday);
          
break;
      }

    }
    
private bool BackupOnlyEXE(string folder)
    {
      
foreach(string file in Directory.GetFiles(folder, "*.exe"))
      {
        FileInfo fi 
= new FileInfo(file);
        File.Copy(fi.FullName, _buFolder 
+ fi.Name);
      }
      
return true;
    }
    
private bool BackupCurrentFolder(string folder)
    {
      
foreach(string file in Directory.GetFiles(folder))
      {
        FileInfo fi 
= new FileInfo(file);
        File.Copy(fi.FullName, _buFolder 
+ fi.Name);
      }
      
return true;
    }

    
private bool BackupAccessedToday(string folder)
    {
      
foreach (string file in Directory.GetFiles(folder))
      {
        
if (File.GetLastAccessTime(file).Date == DateTime.Now.Date)
        {
          FileInfo fi 
= new FileInfo(file);
          File.Copy(fi.FullName, _buFolder 
+ fi.Name);
        }
      }
      
return true;
    }

  }
}
 
static void Main(string[] args)
 {
      BackupUtil bu 
= new BackupUtil("Today");
      
bool ret = bu.Backup("c:\\test\\");
      Console.WriteLine(ret.ToString());
}

 

这个例子中客户端会根据不同的情况对文件进行备份

2、用于异步回调
由于实例化委托是一个对象,所以可以将其作为参数进行传递,也可以将其赋值给属性。这样方法就可以将一个委托作为参数来接受,并且以后可以调用该委托。这称为异步回调,是在较长的进程完成后用来通知调用方的常用方法,以这种方式使用委托时,使用委托的代码无需了解有关使用方法的实现方面的任何信息。
我们假设这样一个场景,我们希望有这样一个函数,对一个整型数组进行过滤,而过滤得条件在编写函数时还不知道,直到使用这个函数的时候可以根据当前的情况编写过滤条件函数,我们使用委托实现如下:

ContractedBlock.gif ExpandedBlockStart.gif Code
public delegate bool IntFilter(int i);
public class Common
    {
        
public static int[] FilterArrayOfInts(int[] ints, IntFilter filter)
        {
            ArrayList aList 
= new ArrayList();
            
foreach (int i in ints)
            {
                
if (filter(i))
                {
                    aList.Add(i);
                }
            }
            
return ((int[])aList.ToArray(typeof(int)));
        }
    }
public class Application
    {
        
public static bool IsOdd(int i)
        {
            
return ((i & 1== 1);
        }
    }
static void Main(string[] args)
        {
            
int[] nums = { 12345678910 };
            
int[] oddNums = Common.FilterArrayOfInts(nums, Application.IsOdd);
            
foreach (int i in oddNums)
                Console.WriteLine(i);
        }

 

结果为:

1
3
5
7
9

 3、多线程编程中使用委托来指定启动一个线程时调用的方法

ContractedBlock.gif ExpandedBlockStart.gif Code
public static void ThreadProc() 
{
        
for (int i = 0; i < 10; i++
    {
            Console.WriteLine(
"ThreadProc: {0}", i);
            
// Yield the rest of the time slice.
            Thread.Sleep(0);
        }
}
public static void Main() 
{
    Thread t 
= new Thread(new ThreadStart(ThreadProc));
}

 

4、C#中的事件模型。用他们指明处理给定事件的方法。
下面我们详细来介绍事件。
四、事件
事件允许类型(或者类型的实例)在某些特定事情发生的时候通知其他对象。
例如button类定义了一个名为click的事件,当buton对象被点击时,应用程序中的一些对象可能希望能够收到一个通知,并执行一些动作。但问题是当我们编写button类的时候并不知道到底要做什么,到底要调用哪些方法,我们只要在使用button的场景才知道到底应该在按下button时做些什么,基于这样的情况,我们想起了委托,我们先在button类中定义一个委托,然后在使用button的相应场景注册这个委托即可,似乎用委托就解决了这个问题了,那事件还有什么用呢,也就是说委托和事件的区别在哪里呢,其实事件就是一种特殊的委托,使用事件委托的类型,必须使用+=进行注册而不能用=,这样做的原因是事件中已经注册的方法不希望被新注册的方法覆盖掉。微软为使用事件定义了一个模式。
事件模式由以下五步组成:
1、定义一个类型用于保存所有需要发送给事件通知接受者的附加信息(继承于System.EventArgs)
2、定义一个委托类型,用于指定事件触发时被调用的方法类型
3、定义一个事件成员
4、定义一个受保护的虚方法,负责通知事件的登记对象
5、定义一个方法,将输入转化为期望的事件
我们这里举一个发Email的时候触发事件的例子:

ContractedBlock.gif ExpandedBlockStart.gif Code
public class MailManager
    {

        
//1、定义一个类型用于保存所有需要发送给事件通知接受者的附加信息(继承于System.EventArgs)

        
public class MailMsgEvernArgs : EventArgs
        {
            
public MailMsgEvernArgs( string from,string to,string subject,string body)
            {
                
this.from = from;
                
this.to = to;
                
this.subject = subject;
                
this.body = body;
                
            }
            
public readonly string from,to,subject,body;
        
        }

        
//2、定义一个委托类型,用于指定事件触发时被调用的方法类型

        
public delegate void MailMsgEventHandler(object sender,MailMsgEvernArgs args);

        
//3、定义一个事件成员

        
public event MailMsgEventHandler MailMsg;

        
//4、定义一个受保护的虚方法,负责通知事件的登记对象

        
protected virtual void OnMailMsg(MailMsgEvernArgs e)
        {
            
if(MailMsg!=null)
                MailMsg(
this,e);
        }
        
//5、定义一个方法,将输入转化为期望的事件
        public void SimulateArrivingMsg(string from,string to,string subject,string body)
        {
            MailMsgEvernArgs e 
= new MailMsgEvernArgs(from,to,subject,body);
            OnMailMsg(e);
        }
    }
static void Main(string[] args)
{    
    MailManager mm 
= new MailManager();
        mm.MailMsg 
+= new MailManager.MailMsgEventHandler(mm_MailMsg);
        mm.MailMsg 
+= new MailManager.MailMsgEventHandler(mm_MailMsg1);
        mm.SimulateArrivingMsg(
"中国""美国""subject""body");
}
private static void mm_MailMsg(object sender, MailManager.MailMsgEvernArgs args)
{

            Console.WriteLine(args.from);
            Console.WriteLine(args.to);
}
private static void mm_MailMsg1(object sender, MailManager.MailMsgEvernArgs args)
{

            Console.WriteLine(args.subject);
            Console.WriteLine(args.body);
}

 

ps:使用EventHandler<(Of <(TEventArgs>)>) 泛型委托 实现事件(来自msdn)

ContractedBlock.gif ExpandedBlockStart.gif Code
// This example demonstrates the EventHandler<T> delegate.

using System;
using System.Collections.Generic;

//---------------------------------------------------------
public class MyEventArgs : EventArgs
{
    
private string msg;

    
public MyEventArgs( string messageData ) {
        msg 
= messageData;
    }
    
public string Message { 
        
get { return msg; } 
        
set { msg = value; }
    }
}
//---------------------------------------------------------
public class HasEvent
{
// Declare an event of delegate type EventHandler of 
// MyEventArgs.

    
public event EventHandler<MyEventArgs> SampleEvent;

    
public void DemoEvent(string val)
    {
    
// Copy to a temporary variable to be thread-safe.
        EventHandler<MyEventArgs> temp = SampleEvent;
        
if (temp != null)
            temp(
thisnew MyEventArgs(val));
    }
}
//---------------------------------------------------------
public class Sample
{
    
public static void Main()
    {
        HasEvent he 
= new HasEvent();
        he.SampleEvent 
+= 
                   
new EventHandler<MyEventArgs>(SampleEventHandler);
        he.DemoEvent(
"Hey there, Bruce!");
        he.DemoEvent(
"How are you today?");
        he.DemoEvent(
"I'm pretty good.");
        he.DemoEvent(
"Thanks for asking!");
    }
    
private static void SampleEventHandler(object src, MyEventArgs mea)
    {
        Console.WriteLine(mea.Message);
    }
}
//---------------------------------------------------------
/*

This example produces the following results:

Hey there, Bruce!
How are you today?
I'm pretty good.
Thanks for asking!

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值