如何使用Invoke传递接口支付宝回调接口参数参数

Java 反射 Method的invoke回调调用任意方法
@author ixenos
&关键子:Method、Field、invoke方法指针/函数指针、回调函数
invoke回调流程示例
0.由Class对象动态构造对应类型对象
1.Class对象的getMethod方法,由方法名和形参构造Method对象
2.Method对象的invoke方法来委托动态构造的对应类型对象,使其执行对应形参的add方法,这是回调函数(方法)的功能
&回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。&
//动态构造InvokeTest类的实例Class&?& classType = InvokeTest.class;
Object invokeTest = classType.newInstance();
//动态构造InvokeTest类的add(int num1, int num2)方法,标记为addMethod的Method对象
Method addMethod = classType.getMethod("add", new Class[]{int.class, int.class});
//动态构造的Method对象invoke委托动态构造的InvokeTest对象,执行对应形参的add方法Object result = addMethod.invoke(invokeTest, new Object[]{1, 2});
//测试输出
System.out.println((Integer)result);
public Method getMethod(String name,
Class&?&... parameterTypes)
throws NoSuchMethodException,
SecurityException返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。name 参数是一个 String,用于指定所需方法的简称。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes 为 null,则按空数组处理。
如果 name 是 "&init&;" 或 "&clinit&",则将引发 NoSuchMethodException。否则,要反映的方法由下面的算法确定(设 C 为此对象所表示的类):
在 C 中搜索任一匹配的方法。如果找不到匹配的方法,则将在 C 的超类上递归调用第 1 步算法。
如果在第 1 步中没有找到任何方法,则在 C 的超接口中搜索匹配的方法。如果找到了这样的方法,则反映该方法。
在 C 类中查找匹配的方法:如果 C 正好声明了一个具有指定名称的公共方法并且恰恰有相同的形参类型,则它就是反映的方法。如果在 C 中找到了多个这样的方法,并且其中有一个方法的返回类型比其他方法的返回类型都特殊,则反映该方法;否则将从中任选一个方法。
注意,类中可以有多个匹配方法,因为尽管 Java 语言禁止类声明带有相同签名但不同返回类型的多个方法,但 Java 虚拟机并不禁止。这增加了虚拟机的灵活性,可以用来实现各种语言特性。例如,可以使用桥方法 (brige method)实现协变返回;桥方法以及将被重写的方法将具有相同的签名,不同的返回类型。
请参阅Java 语言规范 第 8.2 和 8.4 节。
name - 方法名
parameterTypes - 参数列表
与指定的 name 和 parameterTypes 匹配的 Method 对象
NoSuchMethodException - 如果找不到匹配的方法,或者方法名为 "&init&" 或 "&clinit&"
NullPointerException - 如果 name 为 null
SecurityException - 如果存在安全管理器 s,并满足下列任一条件:
调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问方法
调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包
API-Class-getMethod
public Object invoke(Object obj,
Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。
如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。
如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
obj - 从中调用底层方法的对象
args - 用于方法调用的参数
使用参数 args 在 obj 上指派该对象所表示方法的结果
IllegalAccessException - 如果此 Method 对象强制执行 Java 语言访问控制,并且底层方法是不可访问的。
IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明底层方法的类或接口(或其中的子类或实现程序)的实例;如果实参和形参的数量不相同;如果基本参数的解包转换失败;如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。
InvocationTargetException - 如果底层方法抛出异常。
NullPointerException - 如果指定对象为 null,且该方法是一个实例方法。
ExceptionInInitializerError - 如果由此方法引起的初始化失败。
API-Method-invoke
用反射实现获得运行时对象的拷贝的方法(Field类)
1 import java.lang.class;
2 import java.lang.
public class ReflectTester
6   public Object copy(Object object) throws Exception
8     Class&?& classType = object.getClass();
9     Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
10     //获得对象的所有成员变量
11     Field[] fields = classType.getDeclaredFields();
12     for(Field field : fields)
13     {
14       String name = field.getName();
15       //将属性的首字母转换为大写
16       String firstLetter = name.substring(0,1).toUpperCase();
17       //substring(1)表示从index=1开始到最后的子字符串
18       String getMethodName = "get" + firstLetter + name.substring(1);
19       String setMethodName = "set" + firstLetter + name.substring(1);
20       Method getMethod = classType.getMethod(getMethodName, new Class[] {});
21       Method setMethod = classType.setMethod(getMethodName, new Class[] { field.getType() });
22       Object value = getMethod.invoke(object, new Object[] {});
23       setMethod.invoke(objectCopy, new Object[] { value });
24     }
25     return objectC
27   public static void main(String[] args)
29     Customer customer = new Customer("Tom", 20);
30     customer.setId(1L);
32     ReflectTester test = new ReflectTester();
33     Customer customer2 = (Customer) test.copy(customer);
34     System.out.println(customer2.getId() + "," + customer2.getName() + "," + customer2.getAge());
38 Class Customer
40   private float ID;
41   private S
42   private int
43   public Customer()
45     this.ID = 1L;
46     this.name = A;
47     this.age = 1;
49   public Customer(String name, int age)
51     this();
52     this.name =
53     this.age =
55   public void setID(float ID)
57     this.ID = ID;
0.利用Class对象得到对应类型对象&
1.利用Class对象的getDeclaredFields方法,得Field[]数组
2.遍历Field[]数组,构造每一个属性名的字符串,使首字母大写,再连接get字符串,组成setter和getter的命名
3.遍历的同时,getMethod,参数便是要构建的方法名和形参类型,得到各属性的setter和getter方法的Method对象
4.同时,得到方法后,调用各Method对象的invoke委托对应类型对象执行方法(有实参传入,或返回值)
Method的invoke方法能调用任意方法
Method类中的invoke方法,允许调用包装在Method对象中的方法
Object invoke(Object obj, Object... args) //对应隐式参数和显式参数
public Object invoke(Object obj,
Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。
如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。
如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
obj - 从中调用底层方法的对象
args - 用于方法调用的参数
使用参数 args 在 obj 上指派该对象所表示方法的结果
IllegalAccessException - 如果此 Method 对象强制执行 Java 语言访问控制,并且底层方法是不可访问的。
IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明底层方法的类或接口(或其中的子类或实现程序)的实例;如果实参和形参的数量不相同;如果基本参数的解包转换失败;如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。
InvocationTargetException - 如果底层方法抛出异常。
NullPointerException - 如果指定对象为 null,且该方法是一个实例方法。
ExceptionInInitializerError - 如果由此方法引起的初始化失败。
API-Method-invoke
0.如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null
1.第一个参数是隐式参数(比如this,传进你要委托的对象);其余的可变参数提供了显式参数(Java SE 5.0以前没有可变参数,必须传递对象数组或者null)
对于静态方法(属于类),第一个参数设置为null,作为隐式参数来传递
2.如果有返回类型,invoke方法将返回一个名义上的Object类型,实际类型由方法内部决定,所以还要进行强制类型转换;
而因此如果返回类型是基本类型,为了统一返回类型,将会返回其包装器类型:
double s = (Double)m2.invoke(harry) //省略显式参数,因为没有形参,不需要实参传入
&"个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。" &--JDK API 1.6 中文版
invoke的缺点
1.invoke的参数和返回值必需时Object类型的,这意味着必须进行多次的类型转换(特别是基本数据类型),而这将导致编译器错过检查代码的机会,有类型安全的风险,只有到了测试阶段才会发现这些错误,此时找到并改正他们将会更加困难
2.使用反射获得方法指针的代码要比仅仅直接调用方法明显慢一些
3.因此仅在必要时才使用Method对象,而最好使用接口和内部类,不建议Java开发者使用Method对象的回调功能,使用接口进行回调不仅会使代码的运行速度更快,还更易于维护
阅读(...) 评论()java&反射调用有参方法,并传递参数
cla=Class.forName(classpath);
Object o = cla.newInstance();
//下面两种方法是等效的,并注意method.invoke方法参数是可变
//Method method =
cla.getMethod(requestParam,String.class,int.class);
method.invoke(o, new Object[] {request
&,response});
Method method =&Method method =
cla.getMethod(requestParam,new
Class[]{String.class,int.classs});
method.invoke(o, new Object[] {"myname",888});
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate。&
一、为什么Control类提供了Invoke和BeginInvoke机制?
关于这个问题的最主要的原因已经是dotnet程序员众所周知的,我在此费点笔墨再次记录到自己的日志,以便日后提醒一下自己。
1、windows程序消息机制
Windows&GUI程序是基于消息机制的,有个主线程维护着一个消息泵。这个消息泵让windows程序生生不息。
& & & & & & & & & & & & & & &
& & & & & & & & & & & & & & & & & & & & & & & & & Windows&GUI程序的消息循环
Windows程序有个消息队列,窗体上的所有消息是这个队列里面消息的最主要来源。这里的while循环使用了GetMessage()这个方法,这是个阻塞方法,也就是队列为空时方法就会被阻塞,从而这个while循环停止运动,这避免了一个程序把cpu无缘无故地耗尽,让其它程序难以得到响应。当然在某些需要cpu最大限度运动的程序里面就可以使用另外的方法,例如某些3d游戏或者及时战略游戏中,一般会使用PeekMessage()这个方法,它不会被windows阻塞,从而保证整个游戏的流畅和比较高的帧速。
这个主线程维护着整个窗体以及上面的子控件。当它得到一个消息,就会调用DispatchMessage方法派遣消息,这会引起对窗体上的窗口过程的调用。窗口过程里面当然是程序员提供的窗体数据更新代码和其它代码。
2、dotnet里面的消息循环
public static void Main(string[] args)
Form f = new Form();
Application.Run(f);
Dotnet窗体程序封装了上述的while循环,这个循环就是通过Application.Run方法启动的。
3、线程外操作GUI控件的问题
如果从另外一个线程操作windows窗体上的控件,就会和主线程产生竞争,造成不可预料的结果,甚至死锁。因此windows&GUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据,否则就可能产生不可预料的结果。
因此,dotnet里面,为了方便地解决这些问题,Control类实现了ISynchronizeInvoke接口,提供了Invoke和BeginInvoke方法来提供让其它线程更新GUI界面控件的机制。
public interface ISynchronizeInvoke
[HostProtection(SecurityAction.LinkDemand, Synchronization=true, ExternalThreading=true)]
IAsyncResult BeginInvoke(Delegate method, object[] args);
object EndInvoke(IAsyncResult result);
object Invoke(Delegate method, object[] args);
bool InvokeRequired { get; }
如果从线程外操作windows窗体控件,那么就需要使用Invoke或者BeginInvoke方法,通过一个委托把调用封送到控件所属的线程上执行。
二、消息机制---线程间和进程间通信机制
1、window消息发送
Windows消息机制是windows平台上的线程或者进程间通信机制之一。Windows消息值其实就是定义的一个数据结构,最重要的是消息的类型,它就是一个整数;然后就是消息的参数。消息的参数可以表示很多东西。
Windows提供了一些api用来向一个线程的消息队列发送消息。因此,一个线程可以向另一个线程的消息队列发送消息从而告诉对方做什么,这样就完成了线程间的通信。有些api发送消息需要一个窗口句柄,b31.org&这种函数可以把消息发送到指定窗口的主线程消息队列;而有些则可以直接通过线程句柄,把消息发送到该线程消息队列中。
&&&&&&&&&&&&&&&
                              用消息机制通信
SendMessage是windows&api,用来把一个消息发送到一个窗口的消息队列。这个方法是个阻塞方法,也就是操作系统会确保消息的确发送到目的消息队列,并且该消息被处理完毕以后,该函数才返回。返回之前,调用者将会被暂时阻塞。
PostMessage也是一个用来发送消息到窗口消息队列的api函数,但这个方法是非阻塞的。也就是它会马上返回,而不管消息是否真的发送到目的地,也就是调用者不会被阻塞。
2、Invoke&and&BeginInvoke
& & & & & & & & & & & & & &&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&Invoke&or&BeginInvoke
Invoke或者BeginInvoke方法都需要一个委托对象作为参数。委托类似于回调函数的地址,因此调用者通过这两个方法就可以把需要调用的函数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,那么由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。如果其它线程直接操作界面线程所属的控件,那么将会产生竞争条件,造成不可预料的结果。
使用Invoke完成一个委托方法的封送,就类似于使用SendMessage方法来给界面线程发送消息,是一个同步方法。也就是说在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。
使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。
但是在内部实现上,Invoke和BeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。
3、使用场合问题
如果你的后台线程在更新一个UI控件的状态后不需要等待,而是要继续往下处理,那么你就应该使用BeginInvoke来进行异步处理。
如果你的后台线程需要操作UI控件,并且需要等到该操作执行完毕才能继续执行,那么你就应该使用Invoke。否则,在后台线程和主截面线程共享某些状态数据的情况下,如果不同步调用,而是各自继续执行的话,可能会造成执行序列上的问题,虽然不发生死锁,但是会出现不可预料的显示结果或者数据处理错误。
可以看到ISynchronizeInvoke有一个属性,InvokeRequired。这个属性就是用来在编程的时候确定,一个对象访问UI控件的时候是否需要使用Invoke或者BeginInvoke来进行封送。如果不需要那么就可以直接更新。在调用者对象和UI对象同属一个线程的时候这个属性返回false。在后面的代码分析中我们可以看到,Control类对这一属性的实现就是在判断调用者和控件是否属于同一个线程的。
三、Delegate.BeginInvoke
通过一个委托来进行同步方法的异步调用,也是.net提供的异步调用机制之一。但是Delegate.BeginInvoke方法是从ThreadPool取出一个线程来执行这个方法,以获得异步执行效果的。也就是说,如果采用这种方式提交多个异步委托,那么这些调用的顺序无法得到保证。而且由于是使用线程池里面的线程来完成任务,使用频繁,会对系统的性能造成影响。
Delegate.BeginInvoke也是讲一个委托方法封送到其它线程,从而通过异步机制执行一个方法。调用者线程则可以在完成封送以后去继续它的工作。但是这个方法封送到的最终执行线程是运行库从ThreadPool里面选取的一个线程。
这里需要纠正一个误区,那就是Control类上的异步调用BeginInvoke并没有开辟新的线程完成委托任务,而是让界面控件的所属线程完成委托任务的。看来异步操作就是开辟新线程的说法不一定准确。&
四、用Reflector察看一些相关代码
1、Control.BeginInvoke and Control.Invoke
public IAsyncResult BeginInvoke(Delegate method, params object[] args)
using (new MultithreadSafeCallScope())
return (IAsyncResult) this.FindMarshalingControl().MarshaledInvoke(this, method, args, false);
public object Invoke(Delegate method, params object[] args)
using (new MultithreadSafeCallScope())
return this.FindMarshalingControl().MarshaledInvoke(this, method, args, true);
这里的FindMarshalingControl方法通过一个循环向上回溯,从当前控件开始回溯父控件,直到找到最顶级的父控件,用它作为封送对象。例如,我们调用窗体上一个进度条的Invoke方法封送委托,但是实际上会回溯到主窗体,通过这个控件对象来封送委托。因为主窗体是主线程消息队列相关的,发送给主窗体的消息才能发送到界面主线程消息队列。
我们可以看到Invoke和BeginInvoke方法使用了同样的实现,只是MarshaledInvoke方法的最后一个参数值不一样。
2、MarshaledInvoke
private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
if (!this.IsHandleCreated)
throw new InvalidOperationException(SR.GetString("ErrorNoMarshalingThread"));
if (((ActiveXImpl) this.Properties.GetObject(PropActiveXImpl)) != null)
IntSecurity.UnmanagedCode.Demand();
bool flag = false;
if ((SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, this.Handle), out num) == SafeNativeMethods.GetCurrentThreadId()) && synchronous)
flag = true;
ExecutionContext executionContext = null;
if (!flag)
executionContext = ExecutionContext.Capture();
ThreadMethodEntry entry = new ThreadMethodEntry(caller, method, args, synchronous, executionContext);
lock (this)
if (this.threadCallbackList == null)
this.threadCallbackList = new Queue();
lock (this.threadCallbackList)
if (threadCallbackMessage == <span style="color: #)
threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");
this.threadCallbackList.Enqueue(entry);
this.InvokeMarshaledCallbacks();
//终于找到你了,PostMessage
UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
if (!synchronous) //如果是异步,那么马上返回吧
if (!entry.IsCompleted) //同步调用没结束,阻塞起来等待吧
this.WaitForWaitHandle(entry.AsyncWaitHandle);
if (entry.exception != null)
throw entry.
return entry.retV
怎么样,我们终于看到PostMessage了吧?通过windows消息机制实现了封送。而需要封送的委托方法作为消息的参数进行了传递。关于其它的代码这里不作进一步解释。
3、InvokeRequired
public bool InvokeRequired
using (new MultithreadSafeCallScope())
HandleRef ref2;
if (this.IsHandleCreated)
ref2 = new HandleRef(this, this.Handle);
Control wrapper = this.FindMarshalingControl();
if (!wrapper.IsHandleCreated)
return false;
ref2 = new HandleRef(wrapper, wrapper.Handle);
int windowThreadProcessId = SafeNativeMethods.GetWindowThreadProcessId(ref2, out num);
int currentThreadId = SafeNativeMethods.GetCurrentThreadId();
return (windowThreadProcessId != currentThreadId);
终于看到了,这是在判断windows窗体线程和当前的调用者线程是否是同一个,如果是同一个就没有必要封送了,直接访问这个GUI控件吧。否则,就不要那么直接表白了,就需要Invoke或者BeginInvoke做媒了。
阅读(...) 评论()1222人阅读
让我们来看看同步异步的区别:
同步方法调用在程序继续执行之前需要等待同步方法执行完毕返回结果
异步方法则在被调用之后立即返回以便程序在被调用方法完成其任务的同时执行其它操作
.NET框架基类库中有好几种类都可以提供同步和异步的方法调用。
因为同步方法调用会导致程序流程中途等待,所以采用同步方法的情况下往往会导致程序执行的延迟
相比来说,在某些条件下选择异步方法调用就可能更好一些
例如,有的时候程序需要给多个Web服务发出请求,还有远程处理信道(HTTP、TCP)和代理,这时就最好采用异步方法
.NET Framework允许异步调用任何方法,定义与需要调用的方法具有相同签名的委托
CLR将自动为该委托定义添加适当签名的BeginInvoke虚方法和EndInvoke虚方法和Invoke方法。
关于委托的这3个方法的详细说明可以参考这文章
我们先来了解这2个方法和一个委托和一个接口:
BeginInvoke方法用于启动异步调用
它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数,将 AsyncCallback 和 AsyncState(可通过 IAsyncResult 接口的
AsyncState 属性获得)作为最后两个参数,如没有可以为空.
BeginInvoke立即返回,不等待异步调用完成。
BeginInvoke返回IasyncResult,可用于监视调用进度。
结果对象IAsyncResult是从开始操作返回的,并且可用于获取有关异步开始操作是否已完成的状态。
结果对象被传递到结束操作,该操作返回调用的最终返回&#20540;。
在开始操作中可以提供可选的回调。如果提供回调,在调用结束后,将调用该回调;并且回调中的代码可以调用结束操作。
EndInvoke方法用于检索异步调用结果。
在调用BeginInvoke后可随时调用EndInvoke方法,注意:始终在异步调用完成后调用EndInvoke.
如果异步调用未完成,EndInvoke将一直阻塞到异步调用完成。
EndInvoke的参数包括需要异步执行的方法的out和ref参数以及由BeginInvoke返回的IAsyncResult。
要注意的是,始终在异步调用完成后调用EndInvoke
AsyncCallback委托用于指定在开始操作完成后应被调用的方法
AsyncCallback委托被作为开始操作上的第二个到最后一个参数传递
代码原型如下:
[Serializable]
public delegate void AsyncCallback(IAsyncResult ar);
IAsyncResult接口
它表示异步操作的状态.
该接口定义了4个公用属性
下面写一个标准的例子
class&Program
&&&&&&&&static&void&Main(string[]&args)
&&&&&&&&&&&&number&num&=&new&number();
&&&&&&&&&&&&sum&numberadd&=&new&sum(num.numberAdd);
&&&&&&&&&&&&AsyncCallback&numberback&=&new&AsyncCallback(num.CallbackMethod2);
&&&&&&&&&&&&numberadd.BeginInvoke(55,33,numberback,numberadd);
&&&&&&&&&&&&Console.WriteLine(&The&sum&is:&);
&&&&&&&&&&&&Console.WriteLine(num.m);
&&//定义一个执行加法的委托
&&&&public&delegate&int&sum(int&a,&int&b);
&&&&public&class&number
&&&&&&&public&int&m&=&4;
&&&&&&&//定义一个实现此委托签名的方法
&&&&&&&public&int&numberAdd(int&a,&int&b)
&&&&&&&&&&&int&c&=&a&&#43;&b;
&&&&&&&&&&&return&c;
&&&&&&&//定义一个与.net&framework定义的AsyncCallback委托相对应的回调方法
&&&&&&&public&&void&CallbackMethod2(IAsyncResult&ar2)
&&&&&&&&&&&sum&s&=&(sum)ar2.AsyncS
&&&&&&&&&&&int&number&=&s.EndInvoke(ar2);
&&&&&&&&&&&m&=&
&&&&&&&&&&
实际上,发起和完成.NET异步调用有4种方案可供你选择
1.方案1-自己调用EndInvoke方法
异步执行方法的最简单方式是以BeginInvoke开始,对主线程执行一些操作,然后调用EndInvoke,EndInvoke直到异步调用完成后才返回
还是先来段自己喜欢的控制台代码:
&3namespace&ConsoleApplication1
&5&&&&class&Class1
&7&&&&&&&&public&delegate&void&AsyncEventHandler();
&9&&&&&&&&void&Event1()
10&&&&&&&&{
11&&&&&&&&&&&&Console.WriteLine(&Event1&Start&);
12&&&&&&&&&&&&System.Threading.Thread.Sleep(2000);
13&&&&&&&&&&&&Console.WriteLine(&Event1&End&);
14&&&&&&&&}
16&&&&&&&&void&Event2()
17&&&&&&&&{
18&&&&&&&&&&&&Console.WriteLine(&Event2&Start&);
19&&&&&&&&&&&&int&i=1;
20&&&&&&&&&&&&while(i&1000)
21&&&&&&&&&&&&{
22&&&&&&&&&&&&&&&&i=i&#43;1;
23&&&&&&&&&&&&&&&&Console.WriteLine(&Event2&&&#43;i.ToString());
24&&&&&&&&&&&&}
25&&&&&&&&&&&&Console.WriteLine(&Event2&End&);
26&&&&&&&&}
28&&&&&&&&void&CallbackMethod(IAsyncResult&ar)&
29&&&&&&&&{
30&&&&&&&&&&&&((AsyncEventHandler)&ar.AsyncState).EndInvoke(ar);
31&&&&&&&&}
34&&&&&&&&[STAThread]
35&&&&&&&&static&void&Main(string[]&args)
36&&&&&&&&{
37&&&&&&&&&&&&long&start=0;
38&&&&&&&&&&&&long&end=0;
39&&&&&&&&&&&&Class1&c&=&new&Class1();
40&&&&&&&&&&&&Console.WriteLine(&ready&);
41&&&&&&&&&&&&start=DateTime.Now.T
43&&&&&&&&&&&&AsyncEventHandler&asy&=&new&AsyncEventHandler(c.Event1);
44&&&&&&&&&&&&IAsyncResult&ia=asy.BeginInvoke(null,null);
45&&&&&&&&&&&&c.Event2();
46&&&&&&&&&&&&asy.EndInvoke(ia);
47&&&&&&&&&&&&
48&&&&&&&&&&&&end&=DateTime.Now.T
49&&&&&&&&&&&&Console.WriteLine(&时间刻度差=&&#43;&Convert.ToString(end-start)&);
50&&&&&&&&&&&&Console.ReadLine();
51&&&&&&&&}
此程序简单,异步的处理过程在代码43-46这几行
结果如下:
现在让我们来看看同步处理
修改代码43-46这几行代码:
c.Event1();
c.Event2();
结果如下:
前者的时间刻度大大小于后者
我们可以明显地看到异步运行的速度优越性
2.方案2-采用查询(IsCompleted属性)
IAsyncResult.IsCompleted属性获取异步操作是否已完成的指示,发现异步调用何时完成.
再次修改代码43-46这几行代码:
AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
IAsyncResult ia=asy.BeginInvoke(null,null);
c.Event2();
while(!ia.IsCompleted)
asy.EndInvoke(ia);
3.方案3-采用AsyncWaitHandle来等待方法调用的完成
IAsyncResult.AsyncWaitHandle属性获取用于等待异步操作完成的WaitHandle
WaitHandle.WaitOne方法阻塞当前线程,直到当前的WaitHandle收到信号
使用WaitHandle,则在异步调用完成之后,但在通过调用EndInvoke结果之前,可以执行其他处理
再次修改代码43-46这几行代码:
AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
IAsyncResult ia=asy.BeginInvoke(null,null);
c.Event2();
ia.AsyncWaitHandle.WaitOne();
4.方案4-利用回调函数(这个方法比较靠谱 见)
如果启动异步调用的线程不需要处理调用结果,则可以在调用完成时执行回调方法
要使用回调方法,必须将代表该方法的AsyncCallback委托传递给BeginInvoke
再次修改代码43-46这几行代码:
AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
asy.BeginInvoke(new AsyncCallback(c.CallbackMethod),asy);
c.Event2();
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:930450次
积分:12061
积分:12061
排名:第1317名
原创:169篇
转载:610篇
评论:122条
(32)(53)(1)(11)(10)(28)(10)(9)(19)(20)(25)(18)(6)(17)(24)(47)(4)(9)(41)(21)(19)(8)(9)(15)(19)(4)(4)(3)(8)(16)(22)(24)(6)(8)(15)(15)(10)(9)(15)(15)(5)(11)(10)(1)(27)(17)(2)(2)(4)(2)(9)(1)(1)(2)(3)(3)(23)(9)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 回调函数参数传递 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信