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();
}
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();
}
相关文章推荐
- C# Windows API应用之GetDesktopWindow ——获得桌面所有窗口句柄的方法
- 多播委托——GetInvocationList方法
- C# Windows API应用之基于GetDesktopWindow获得桌面所有窗口句柄的方法
- C#编程应用--线程与委托
- [C#应用]得到组件事件的委托列表
- C#中委托和事件在观察者模式中的应用实例
- C# []、List、Array、ArrayList 区别及应用
- 异步委托的应用(二) 有返回值的应用
- C# 委托事件的应用
- C# 委托应用总结
- C# []、List、Array、ArrayList 区别及应用
- c#List.Sort(比较的方法)返回值意义
- VC Windows API应用之GetDesktopWindow ——获得桌面所有窗口句柄的方法
- C#之正则表达式、异常处理和委托与事件
- C# 泛型委托应用
- C# []、List、Array、ArrayList 区别及应用
- C# 委托应用总结
- c#devexpres TreeList 最简单显示动态值的应用
- C#/.NET中委托和事件的机制和应用
- How to get Android Phone ServiceState - APK应用如何获得Android Phone的ServiceState,两种方法