如果你对Windows Workflow Foundation(WF)一无所知,当看到扩展C#与元编程(一)中由MW编译器生成的FirstLook.mw.cs时,也许这么在想:我KAO,这是C#版的汇编语言!
WF到底是什么?可以这么认为:WF runtime是高级版的CLR(CLR上的CLR),activity是高级版的MSIL指令(可以勉强这么比喻),Metah.W是高级版的C#。
Activity可以分为两类:primitive activity和composite activity。Primitive activity继承自 System.Activities.NativeActivity
, System.Activities.NativeActivity<T>
等,用来实现流程控制容器,如sequence, if-else, while, foreach, try-catch-finally等:
namespace System.Activities.Statements { public sealed class Sequence : NativeActivity { public Sequence(); public Collection<Variable> Variables { get; } public Collection<Activity> Activities { get; } //... } public sealed class If : NativeActivity { public If(); public InArgument<bool> Condition { get; set; } public Activity Then { get; set; } public Activity Else { get; set; } //... } public sealed class While : NativeActivity { public While(); public Collection<Variable> Variables { get; } public Activity<bool> Condition { get; set; } public Activity Body { get; set; } //... } public sealed class ForEach<T> : NativeActivity { public ForEach(); public InArgument<IEnumerable<T>> Values { get; set; } public ActivityAction<T> Body { get; set; } //... } public sealed class TryCatch : NativeActivity { public TryCatch(); public Activity Try { get; set; } public Collection<Catch> Catches { get; } public Activity Finally { get; set; } //... } }
WF这个高级CLR令人拍手称快的特性之一是,你可以自定义流程控制容器(可以想象成自定义MSIL指令),比如高大上的状态机:
namespace System.Activities.Statements { public sealed class StateMachine : NativeActivity { public StateMachine(); public Collection<Variable> Variables { get; } public State InitialState { get; set; } public Collection<State> States { get; } //... } public sealed class State { public State(); public bool IsFinal { get; set; } public Collection<Variable> Variables { get; } public Activity Entry { get; set; } public Activity Exit { get; set; } public Collection<Transition> Transitions { get; } //... } public sealed class Transition { public Transition(); public Activity Trigger { get; set; } public Activity<bool> Condition { get; set; } public Activity Action { get; set; } public State To { get; set; } //... } }
SecondLook.mw展示了如何使用状态机:
一个statemachine至少包含一个common state及一个final state,每个state由唯一的label标识,如 InPark
, InNeutral
等, break
关键字标明这是一个final state, statemachine
关键字后的 goto
clause标明initial common state,当流程进入某common state后,首先执行 ~>
所标识的entry statement,接着执行 on
关键字标识的trigger statement,接着依顺序执行 if
关键字标识的condition expression,如果某condition评估为true,则执行 <~
所标识的exit statement和 do
关键字标识的action statement(SecondLook.mw中未使用),接着跳转到 goto
关键字所标识的state,如果所有的condition expression都评估为false,则重新执行该state的trigger statement。如果某final state执行完毕,则该statemachine执行完毕。
MW编译器将activity Drive
翻译成下面的C#代码:
//SecondLook.mw.cs, generated by MW compiler namespace HelloMW.SecondLook { class Drive : global::System.Activities.Activity { private global::System.Activities.Activity __GetImplementation__() { global::System.Activities.Activity __vroot__; { var __v__0 = new global::System.Activities.Statements.Sequence(); var isMoved = new global::System.Activities.Variable<bool>(); __v__0.Variables.Add(isMoved); __v__0.Activities.Add(new global::MetahWActionActivity(__ctx__ => { isMoved.SetEx(__ctx__, false); } )); var __v__1 = new global::System.Activities.Statements.While(); __v__1.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => !isMoved.Get(__ctx__)); { var __v__2 = new global::System.Activities.Statements.Sequence(); { var __v__3 = new global::System.Activities.Statements.StateMachine(); var action = new global::System.Activities.Variable<DriveAction>(); __v__3.Variables.Add(action); var __v__4 = new global::System.Activities.Statements.State(); var __v__5 = new global::System.Activities.Statements.Transition(); var __v__6 = new global::System.Activities.Statements.State(); var __v__7 = new global::System.Activities.Statements.Transition(); var __v__8 = new global::System.Activities.Statements.Transition(); var __v__9 = new global::System.Activities.Statements.Transition(); var __v__10 = new global::System.Activities.Statements.State(); var __v__11 = new global::System.Activities.Statements.Transition(); var __v__12 = new global::System.Activities.Statements.State(); var __v__13 = new global::System.Activities.Statements.Transition(); var __v__14 = new global::System.Activities.Statements.State(); { __v__3.States.Add(__v__4); __v__4.Entry = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Enter InPark"); } ); __v__4.Exit = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Exit InPark"); } ); __v__5.Trigger = new GetDriveAction().Initialize(__activity2__ => { __activity2__.Result = new global::System.Activities.OutArgument<global::HelloMW.SecondLook.DriveAction>(new global::MetahWLocationActivity<global::HelloMW.SecondLook.DriveAction>(action)); } ); __v__5.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => action.Get(__ctx__) == DriveAction.Neutral); __v__4.Transitions.Add(__v__5); } { __v__3.States.Add(__v__6); __v__6.Entry = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Enter InNeutral"); } ); __v__6.Exit = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Exit InNeutral"); } ); __v__7.Trigger = new GetDriveAction().Initialize(__activity2__ => { __activity2__.Result = new global::System.Activities.OutArgument<global::HelloMW.SecondLook.DriveAction>(new global::MetahWLocationActivity<global::HelloMW.SecondLook.DriveAction>(action)); } ); __v__7.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => action.Get(__ctx__) == DriveAction.Forward); __v__6.Transitions.Add(__v__7); __v__8.Trigger = __v__7.Trigger; __v__8.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => action.Get(__ctx__) == DriveAction.Reverse); __v__6.Transitions.Add(__v__8); __v__9.Trigger = __v__7.Trigger; __v__9.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => action.Get(__ctx__) == DriveAction.TurnOff); __v__6.Transitions.Add(__v__9); } { __v__3.States.Add(__v__10); __v__10.Entry = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Enter InForward"); isMoved.SetEx(__ctx__, true); } ); __v__10.Exit = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Exit InForward"); } ); __v__11.Trigger = new GetDriveAction().Initialize(__activity2__ => { __activity2__.Result = new global::System.Activities.OutArgument<global::HelloMW.SecondLook.DriveAction>(new global::MetahWLocationActivity<global::HelloMW.SecondLook.DriveAction>(action)); } ); __v__11.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => action.Get(__ctx__) == DriveAction.Neutral); __v__10.Transitions.Add(__v__11); } { __v__3.States.Add(__v__12); __v__12.Entry = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Enter InReverse"); isMoved.SetEx(__ctx__, true); } ); __v__12.Exit = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("Exit InReverse"); } ); __v__13.Trigger = new GetDriveAction().Initialize(__activity2__ => { __activity2__.Result = new global::System.Activities.OutArgument<global::HelloMW.SecondLook.DriveAction>(new global::MetahWLocationActivity<global::HelloMW.SecondLook.DriveAction>(action)); } ); __v__13.Condition = new global::MetahWFuncActivity<bool>(__ctx__ => action.Get(__ctx__) == DriveAction.Neutral); __v__12.Transitions.Add(__v__13); } { __v__3.States.Add(__v__14); __v__14.IsFinal = true; __v__14.Entry = new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("TurnedOff"); } ); } __v__3.InitialState = __v__4; __v__5.To = __v__6; __v__7.To = __v__10; __v__8.To = __v__12; __v__9.To = __v__14; __v__11.To = __v__6; __v__13.To = __v__6; __v__2.Activities.Add(__v__3); } __v__2.Activities.Add(new global::MetahWActionActivity(__ctx__ => { Console.WriteLine("isMoved: " + isMoved.Get(__ctx__)); } )); __v__1.Body = __v__2; } __v__0.Activities.Add(__v__1); __vroot__ = __v__0; } return __vroot__; } private global::System.Func<global::System.Activities.Activity> __implementation__; protected override global::System.Func<global::System.Activities.Activity> Implementation { get { return __implementation__ ?? (__implementation__ = __GetImplementation__); } set { throw new global::System.NotSupportedException(); } } } }
下面是可能的执行结果:
Enter InPark !action: Neutral Exit InPark Enter InNeutral !action: Reverse Exit InNeutral Enter InReverse !action: TurnOff !action: Forward !action: Neutral Exit InReverse Enter InNeutral !action: Forward Exit InNeutral Enter InForward !action: Forward !action: Forward !action: Reverse !action: Neutral Exit InForward Enter InNeutral !action: TurnOff Exit InNeutral TurnedOff isMoved: True 请按任意键继续. . .
Composite activity直接继承自 System.Activities.Activity
或 System.Activities.Activity<T>
,它由其它primitive activity和/或composite activity组合而成。Metah.W和WF designer只能创作composite activity。
我不知道大家怎么看待微软这家公司,多数时候,MS是家缺乏想象力但做事超级认真的公司,有时它能创造出一些令人眼前一亮的作品,C#从第二版开始就一直闪亮,WF也是一个极富想象力的技术,不过,WF现在还是个藏在深山中的璞玉,希望此文能激起你研究WF的兴趣。关于
Metah.W: A Workflow Metaprogramming的更多信息请访问: https://github.com/knat/Metah 。
待续。