If you are not familiar with what CPS is, we recommend several links (hopefully your English will be awesome ):
Http://blogs.msdn.com/ B /wesdyer/archive/2007/12/22/continuation-passing-style.aspx
Http://en.wikipedia.org/wiki/Continuation-passing_style
Http://blogs.msdn.com/ B /ericlippert/archive/2010/10/22/continuation-passing-style-revisited-part-two-handwaving-about-control-flow.aspx
CPS (continuation-Passing Style): it can be understood as a subsequent transfer format, which is a feature in functional programming. However, the combination of lambda expressions and action <t> generic delegation in C # can achieve this feature well.
Previously, we used a structured approach to handle exceptions:
Void Q ()
{
Try
{
B (());
}
Catch
{
C ();
}
D ();
}
Int A (int)
{
Throw;
Return 0; // inaccessible, temporarily ignored
}
Void B (INT X) {// To Do Something}
Void C () {// To Do Something}
Void D () {// To Do Something}
Whether these method calls are object-oriented is not a topic to be discussed. However, try {...} catch {...} finally {...}, a structured exception handling method, is still widely used.
A structural feature with strong coupling and high correlation. It is closely integrated like an assembly line.
Let's take a look at the call process:
First, execute method A. If method A does not produce any exception, return the result to Method B as a parameter and call Method B. If Method B runs normally. Method C will not be executed, and it will jump directly to method D to start execution.
If either method A or method B has an exception, the execution will be suspended. The call will jump to method C for execution (the premise is that the exception can be captured smoothly ). Finally, call method D.
In fact, when CLR adopts a structured exception handling mechanism, it implements some internal and language mechanisms such as handsome selector and processor. For details, refer to CLR via C #3.0. However, since we say that this exception handling method is interlocking and similar to streaming, why can't we simulate the use of CPS?
For the four methods of ABCD, we consider two cases (in fact, it is an if... else .... structure): method call succeeded; method call failed.
Therefore, you can define it as follows:
Action <t>: accept a parameter of type T with no return value;
Void A (Action <int> normal, Action error );
Void B (INT X, Action normal, Action error) {whatever}
Void C (Action normal, Action error) {whatever}
Void D (Action normal, Action error) {whatever}
Note: All normal operations can be imagined as: we usually do not consider the abnormal method bodies. All errors can be considered as the handling methods for exceptions in the original method bodies.
The processing logic of the try block is abstracted:
Try (
/* Trybody */(bodynormal, bodyerror) => (
/* Normal for a */x => B (X, bodynormal, bodyerror ),
/* Error for a */bodyerror ),
/* Catchbody */C,
/* Outernormal */() => D (qnormal, qerror ),
/* Outererror */qerror );
First, the try block can only have two egress ports:
Run the following command by try --> outernormal: () => D (qnormal, qerror) with outernormal
Try --> catchbody: () => C (outernormal, outererror): () => C () => D (qnormal, qerror), outererror)
For try objects, there are:(Bodynormal, bodyerror) => A (x => B (X, bodynormal, bodyerror), bodyerror );
Therefore, the expansion is as follows:
A (
X => B (// A's normal continuation
X, // B's argument
() => D (// B's normal continuation
Qnormal, // D's normal continuation
Qerror), // D's error continuation
() => C (// B's error continuation
() => D (// C's normal continuation
Qnormal, // D's normal continuation
Qerror) , // D's error continuation
Qerror), // C's error continuation
() => C (// A's error continuation
() => D (// C's normal continuation
Qnormal, // D's normal continuation
Qerror) , // D's error continuation
Qerror) // C's error continuation
If C throws an exception, continuation is immediately transferred to qerror for execution;
In terms of readability, this is certainly not a very good implementation method. However, this is an idea. We can use this method when writing some highly correlated method calls, and there are not many method calls.
The following implementation demonstrates the transfer of CPS's stream calling (pseudo recursion) and data processing control:
Implement factorial:
Static voidMain () {factorial (5, x =>Console. Writeline (x ));}Static voidFactorial (IntN,Action<Int> K ){If(N = 0) K (1 );ElseFactorial (n-1, x => K (N * X ));}
Of course, CPS also has a very useful feature that supports asynchronous callback and is useful in asynchronous programming.