C#委托—GetInvocationList()的应用(获得多个返回值与异常处理)

   在上节中程序Program1中,我们发现触发事件时,订阅者发生了“值覆盖”的现象。那么有没有方法可以返回多个返回值呢?答案时肯定的。委托的定义在编译时会生成一个继承自MulticastDelegate的类,而这个MulticastDelegate又继承自Delegate,在Delegate内部,维护类一个委托链表,链表上的每个元素,为一个只包含一个目标方法的委托对象。而通过以下几个步骤来获得每个委托对象的返回值

1.       通过Delegate基类的GetInvocationList()静态方法,获得这个委托链表,

2.       通过遍历这个链表,

3.       为每个委托对象来调用方法,将返回值保存在起来。

例子:

 


    
class  Delegater1
    {
        
static   void  Main( string [] args)
        {
            Publishser pu 
=   new  Publishser();
            Subscriber1 s1 
=   new  Subscriber1();
            Subscriber2 s2 
=   new  Subscriber2();
            Subscriber3 s3 
=   new  Subscriber3();

            pu.Eventr 
+=  s1.Outer;
            pu.Eventr 
+=  s2.Outer;
            pu.Eventr 
+=  s3.Outer; // 到此为止,有3个订阅者注册了Eventr事件,在下面触发事件的时候这三个订阅者会被依次执行,但最终的只会有一个返回值
            pu.InvokeEventr(); // 触发事件
            Console.ReadLine();
        }
    }

    
// 定义委托
     public   delegate   string  Delegater();

    
// 定义事件发布者
     class  Publishser
    {
        
// 定义事件
         public   event  Delegater Eventr;

        
public   void  InvokeEventr() // 触发事件
        {
            Delegater delegater 
=  Eventr;
            
if  (delegater  !=   null )
            {
                List
< string >  ls  =   new  List < string > ();
                
// 获得目标对象的委托数组
                Delegate[] delarr  =  Eventr.GetInvocationList();
                
// 遍历委托数组
                 foreach (Delegate del  in  delarr)
                {
                    
// 强制转换为具体的委托类型
                    Delegater er  =  (Delegater)del;
                    
// 调用方法
                    ls.Add(er());
                }
                
foreach ( string  str  in  ls)
                {
                    Console.WriteLine(
" {0} " ,str);
                }

            }
         
        }
    }

    
// 定义事件订阅者
     class  Subscriber1
    {
        
public   string  Outer()
        {
            Console.WriteLine(
" this is Subscriber1 " );
            
return   " Subscriber1 Outer " ;
        }
    }

    
class  Subscriber2
    {
        
public   string  Outer()
        {
            Console.WriteLine(
" this is Subscriber2 " );
            
return   " Subscriber2 Outer " ;
        }
    }

    
class  Subscriber3
    {
        
public   string  Outer()
        {
            Console.WriteLine(
" this is Subscriber3 " );
            
return   " Subscriber3 Outer " ;
        }
    }

 

 

 

结果:

 

this is Subscriber1 

 

this is Subscriber2 

 

this is Subscriber3 

 

Subscriber1 Outer 

 

Subscriber2 Outer 

 

Subscriber3 Outer

以上方法最常见的应用场合就是异常处理,因为在触发事件的时候,订阅者的方法很有可能抛出异常,而这个异常会直接影响到发布者,使得发布者程序终止,而使得后面的订阅者的方法无法被执行。这显然不是我们想要的效果,所以我们通过上面的方法先获取委托链表,然后遍历单独执行每个目标委托对象的方法,并做相应的try{} catch{}。这样避免上述抛出异常后影响后面的订阅者的问题。

例子:

 

结果:

this is Subscriber1

Exception:调用的目标发生了异常

this is Subscriber3

   我们注意到GetInvocationList()来获得所有订阅者的方法,所以我们必须要定义Delegate[]来接收,然后再强制转换下去,才能调用注册对象的方法,下面介绍一种比较灵活的方法:

 

它是定义在Delegate基类中的DynamicInvoke()方法:

public object DynamicInvoke(params object[] args);

    这可能是委托最通用的方法来,适用于所有类型的委托。它的接受的参数为object[],即任意数量的任意类型都可作为参数,并放回一个object对象

所以上面的方法也可以这样写:

    这个时候你可以发现可以将这个方法抽象出来,使它成为一个公共的方法,供其他类条用,将这个方法设为静态。

//  触发某个事件,以列表形式返回所有方法的返回值
public   static   object [] FireEvent(Delegate del,  params   object [] args){

    List
< object >  objList  =   new  List < object > ();

    
if  (del  !=   null ) {
        Delegate[] delArray 
=  del.GetInvocationList();
        
foreach  (Delegate method  in  delArray) {
            
try  {
                
//  使用DynamicInvoke方法触发事件
                 object  obj  =  method.DynamicInvoke(args);
                
if  (obj  !=   null )
                    objList.Add(obj);
            } 
catch  { }
        }
    }
    
return  objList.ToArray();
}

转载于:https://www.cnblogs.com/xinzaitian/archive/2009/11/12/1601537.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值