浅析关于C#中的委托和事件(一)

本文深入讲解C#中的委托概念,包括定义、使用方法及应用场景,通过实例演示如何利用委托简化程序设计并提供灵活的日志记录解决方案。

什么是委托?.NET Framework的联机丛书中的解释是:委托是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用和可以像其它任何方法一样,具有参数和返回值。通过查询其它技术文档,我们可以这样理解委托:委托通过引用把方法包裹起来,并使方法有一个有效的返回值,他的目的就是实现了动词(方法)的名词(委托)化。

大多数情况下,当我们需要调用方法(也就是函数,但在面向对象的程序设计中,我们尽量要少说或不说“函数”,而用方法代之。当然构造函数和析构函数除外)时我们会制定要直接调用的函数。比如类MyClass有一个Action()的方法,我们通常会这样调用:

//注意该代码段无法直接编译运行;

MyClass mc = new MyClass();

mc.Action();

然而有时我们不想直接调用方法,我们希望能让其它的使用者也来调用,或者我们希望在方法被调用时能产生些记录出来,记录的方式并不是预先制定的(输出到控制台,写到文本文件或输出到Message Box等均可)。这时候如果还是按照原来的方式我们的代码可能会变得比较复杂。幸好C#给我们提供了委托让我们能很轻松地实现。首先我们看以下实例,我们有这样一个类:

//注意该代码段无法直接编译运行;

public class MyClass

{

         public void Action()

         {

                   //方法记录开始;

                   Console.WriteLine(“Action() method starts…”);

                   //程序其它代码继续进行….

                   //方法记录结束;

                   Console.WriteLine(“Action() method finish…”);

}

}

Action()方法中的开始和结束都有一段关于方法开始和结束的文本会在其开始后和结束前输出到控制台,实现了运行记录。但我们这样做也仅能到此为止,如果想把记录输出到文本文件,我们不得不再重新改写Action()方法。代码开始变得复杂。

怎样不写复杂的代码而又能实现我们的目的呢?接下来看委托给我们提供的解决方法。首先我们先写一个委托类MyDelegate,该类有一个带参数不带返回值的代理,代码如下:

//注意该代码段无法直接编译运行;

public class MyDelegate

{

         public delegate void LogHandler(string message);         

}

然后改写我们的MyClass类如下:

public class MyClass

{

         public void Action(MyDelegate .LogHandler lh)

         {

                   //方法记录开始;

                   if(lh != null)

                            lh(“Action() method starts…”);

                   //程序其它代码继续进行….

                   //方法记录结束;

                   if(lh != null)

                            lh(“Action() method finish…”);

}

}

在该类中,我们的Action方法有一个MyDelegate .LogHandler的委托参数。我们需要注意的是,在使用委托的实例lh之前我们需要有个非空判断if(lh != null),这个判断让我们检查该委托是否已指向一个方法(在这里应该是“记录”方法)。接下来我们继续完成我们的“记录”方法,我仍然把它放到一个单独的类MyLog中,代码如下:

//注意该代码段无法直接编译运行;

public class MyLog

{

         public void Logger(string logInfo)

         {

                   Console.WriteLine(logInfo);

}

}

需要特别注意的是,MyLog.Logger方法和我们的MyDelegate.LogHandler方法结构一样:都是带有一个字符串参数且无返回值。

接下来的工作就是要在Main()方法中测试委托给我们实现的效果了,代码如下:

//注意该代码段无法直接编译运行;

public class DelegateTest

{

         public static void Main()

         {

                   MyClass mc = new MyClass();

                   MyDelegate. LogHandler lh = new MyDelegate. LogHandler (MyLog.Logger);

                   mc.Action(lh);

}

}

至此,委托已经给我实现了预期的目标。如果我们想把“记录”的方式改为输出到文本的话只需要修改MyLog.Logger方法即可。所有程序完整代码如下:

//该代码可以直接编译运行;
using System;
namespace DelegateTester
{
    
public class MyDelegate
    
{
        
public delegate void LogHandler(string message);
    }


    
public class MyClass
    
{
        
public void Action(MyDelegate.LogHandler lh)
        
{
            
//Log handling begins;
            if (lh != null)
                lh(
"Action method starts...");
            
//Other code about Action method;
            Console.WriteLine("Hi, I am the mothod Action, I am running^_^...");
            
//Log handling finish;
            if (lh != null)
                lh(
"Action method findish...");
        }

    }


    
public class MyLog
    
{
        
public static void Logger(string message)
        
{
            
//Just output to console. You can output to file too.
            Console.WriteLine(message);
        }

    }

    
class Program
    
{
        
static void Main(string[] args)
        
{
            MyClass mc 
= new MyClass();
            MyDelegate.LogHandler lh 
= new MyDelegate.LogHandler(MyLog.Logger);
            mc.Action(lh);
        }

    }

}

以上是委托应用的典型实例,根据联机丛书的说明我们可以在如下情况下使用委托:

         当使用事件设计模式时;

当封装静态方法可取时;

当调用方不需要访问实现该方法的对象中的其他属性、方法或接口时;

需要方便的组合;

当类可能需要该方法的多个实现时。

以下代码为我写的委托的另一个简单应用——367型彩票应用。

 

//该代码可以直接编译运行;
using System;
namespace SingleDelegate
{
    
class Program
    
{
        
public delegate int[] Generator(int start, int end, int length);
        
static int[] GenerateNumber(int start, int end, int length)
        
{
            
int[] outNumber = new int[length];
            Random r 
= new Random();
            
for (int i = 0; i < length; i++)
            
{
                outNumber[i] 
= r.Next(start, end);
                
if (i > 0)
                
{
                    
for (int j = 0; j < i; j++)
                    
{
                        
while (outNumber[j] == outNumber[i])
                            outNumber[i] 
= r.Next(start, end);
                    }

                }

            }

            Array.Sort(outNumber);
            
return outNumber;
        }


        
static void Main(string[] args)
        
{
            Console.WriteLine(
"36选7(无重复)号码为: ");
            Generator g 
= new Generator(GenerateNumber);
            
foreach (int n in g(1367))
            
{
                Console.Write(n 
+ " ");
            }

        }

    }

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值