您的位置:首页 > 编程语言 > C#

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

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

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

2. [/b]通过遍历这个链表,[/b]

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

例子:

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

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

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

public object DynamicInvoke(params object[] args);

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

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

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

// 触发某个事件,以列表形式返回所有方法的返回值
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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: