WF學習系列之三:RuleSet知識點概述
|
注:學習RuleSet真的需要耐心,就想我們小學的時候學習加減乘除的時候,首先是了解規則,然后是多加練習,最后才能熟練運用。這個學習的過程是一個反復的過程,就如辯證法所講的那樣:理論-實踐-理論。
|
RuleSet 由一個或多個規則條件及其導致的操作組成。可以將規則視為 IF-THEN-ELSE 語句,其中,條件對應于 IF,而操作定義 THEN 和 ELSE 子句的行為。
操作可以執行以下任務:
· 設置工作流上的字段或屬性。
· 調用工作流上或工作流中的對象上的方法。
· 調用被引用程序集中的類型上的靜態方法。
· 執行 Halt 或 Update 語句。
· Windows Workflow Foundation 規則引擎設計為以基于優先級的方式運行規則并且支持正向鏈接。
1規則集中的規則計算
規則技術在 Windows Workflow Foundation 中以兩種主要方式展現:
作為活動的條件。
作為 PolicyActivity 活動中的正向鏈接規則集。
本節稍后的部分將討論正向鏈接,但是簡而言之,它是指一種能力,這種能力使一個規則的操作可以導致其他相關規則被重新計算。
開發人員使用規則條件而不是代碼條件的主要原因是,規則條件已成為模型的一部分,并且可在執行工作流實例時進行運行時動態更新。 規則條件的第二個優點是,在其成為模型的一部分之后,可在該模型的基礎之上生成更多復雜的工具,以提供額外的創作體驗、依賴關系管理、跨條件分析等等。
PolicyActivity 活動封裝了 RuleSet 的定義和執行。 RuleSet 是具有一組執行語義的規則的集合。 而規則就是對工作流成員進行操作的 If-Then-Else 表達式。
規則計算
RuleSet 中的每條規則都有默認值為“0”的優先級值。 可以將 RuleSet 中的規則視為一個有序集合,該集合按優先級值排序。 Windows Workflow Foundation 規則計算器逐條計算規則,并根據規則條件的計算結果執行該規則的操作。
計算機制從概念上可描述為:
1 從活動規則的列表開始。
2 查找優先級最高的規則。
3 計算該規則,然后相應地執行其 Then/Else 操作。
4 如果某條規則的操作更新某個字段或屬性,并且該字段或屬性由列表中前面的一條或多條規則(這些規則具有更高的優先級)的條件所使用,則重新計算前面的這些規則。
注意:
只有那些有著特定依賴關系的規則才會被重新計算。
5 繼續執行該過程,直至 RuleSet 中的所有規則都已計算(或者執行了 Halt)。
在下面的概念性示例中,假定有下面的規則集,其中“A”、“B”等等表示工作流中的數據。
Rule 4 (Priority = 4)
IF A = 15
THEN B = 5
Rule 3 (Priority = 3)
IF C = 5
THEN B = 10
Rule 2 (Priority 2)
IF D = 2
THEN A = 15
Rule 1 (Priority 1)
IF B = 5
THEN E = 7假定有以下輸入數據:
A =0
B = 0
C = 5
D = 2
E = 0
計算過程將按如下方式繼續:
計算規則 4;計算結果為 false,因為它沒有 Else 操作,所以不執行任何操作。
規則 3 的計算結果為 true,因此執行其操作,設置 B = 10。規則 4 不依賴于 B 的值;因此,計算過程繼續執行至規則 2。
規則 2 的計算結果為 true,因此執行其操作,設置 A = 15。
規則 3 和 2 不會重新計算,因為它們的條件不依賴于 A 的值。但是,由于規則 4 在其條件中使用了 A 的值,因此它將被重新計算。 它的計算結果為 true,因此執行其操作,設置 B = 5。規則 4、3 和 2 不依賴于 B 的值,因此,計算過程繼續執行至規則 1。
規則 1 的計算結果為 true,因此執行其操作,設置 E = 7。
現在,結果數據集如下所示:
A = 15
B = 5
C = 5
D = 2
E = 7
2根據優先級執行 RuleSet
如前所述,如果要以某種順序執行 RuleSet 或該 RuleSet 中規則的子集,則可以使用規則上的優先級字段精確定義此順序。 經常這樣做可以避免進行鏈接,甚至在這些方案中可以關閉鏈接。
請注意,使用 Windows Workflow Foundation 中的正向執行機制可以定義執行順序,但并不要求您這樣做。大多數情況下,通過正向鏈接行為就可以獲得正確的 RuleSet 結果,不必分配規則優先級,這是因為引擎自動管理各種關系,可以確保規則依賴關系得到滿足。
以下示例說明了這一點。
Rule 1
IF this.Weather.Temperature < 50
THEN this.Drink.Style = "Latte"
Rule 2
IF this.Drink.Style == "Latte"
THEN this.Snack.Style = "Scone"
ELSE this.Snack.Style = "Muffin"
在 Windows Workflow Foundation 中可以對規則 1 提供更高的優先級,以使其首先執行。 這樣可以確保在計算規則 2 之前設置 Drink.Style。
但是,并非一定需要排序才能獲得所需的結果。 假定首先計算規則 2。 在此情況下,Drink.Style 可能為空,也可能為其他樣式。 這會導致將 Snack.Style 設置為“Muffin”。 但是,執行規則 1 并將 Drink.Style 設置為“Latte”之后,就會重新計算規則 2,并會將 Snack.Style 設置為“Scone”。 實質上,您可以控制排序,但許多情況下不必這樣做。
如果規則有依賴關系,則排序可能也很有用,但在本應需要顯式 Update 語句或方法屬性設置的情況卻不必這樣做。
3處理規則中的集合
在某些情況下,可能必須分別根據集合中的所有項計算規則。可通過多種方法來迭代集合,但其中一種方法是使用規則模式,如下所示:
Rule 1 (Priority = 2) // always execute this rule once to create the enumerator
IF 1==1
THEN this.enumerator = this.myCollection.GetEnumerator()
Rule 2 (Priority = 1)
IF this.enumerator.MoveNext()
THEN this.currentInstance = this.enumerator.Current
Rules 3-N (Priority = 0)
.... // Additional rules written against this.currentInstance
Rule N+1 (Priority = -1)
// can be any condition as long as it is evaluated every time;
// this.currentInstance will be evaluated each time this.currentInstance changes, whereas
// "1==1" would only be evaluated once.
IF this.currentInstance == this.currentInstance
THEN ...
Update("this/enumerator") //this will cause Rule 2 to be reevaluated
ELSE ...
Update("this/enumerator")
4規則的正向鏈接
鏈接基于規則中標識的依賴項;更具體而言,基于一個規則的操作和其他規則的條件中的依賴項。 可以通過以下三種方式之一標識或聲明這些依賴項:
隱式
基于屬性
顯式
(1) 隱式
隱式依賴項由工作流運行時引擎自動標識。 當首次執行 RuleSet 時,將分析每個規則以評估其在自己的條件中讀取并在操作中寫入的字段/屬性。這是通過遍歷條件中的表達式和操作中的語句來完成的。 例如,假定有以下規則:
Rule 1
IF this.discount > 0
THEN this.total = (1-this.discount) * this.subtotal
Rule 2
IF this.subtotal > 10000
THEN this.discount = 0.05
工作流運行時引擎將計算這些規則,確定規則 1 讀取折扣和小計字段,并寫入合計字段。 規則 2 讀取小計字段并寫入折扣字段;因此,規則 2 上有規則 1 的依賴項。結果是工作流運行時引擎將確保每當規則 2 運行 Then 操作時就會計算或重新計算規則 1。
依賴項在葉節點級別進行標識,如下面的 RuleSet 示例所示。
Rule 1
IF this.order.Discount > 0
THEN this.order.Total = (1-this.order.Discount) * this.order.Subtotal
Rule 2
IF this.order.Subtotal > 10000
THEN this.order.Discount= 0.05
Rule 3
IF this.order.CustomerType = "Residential"
THEN ...
仍會標識規則 1 和規則 2 之間的依賴關系。但是,在規則 1 或規則 2 上沒有規則 3 的依賴項,因為它們兩個都不更新 CustomerType 屬性。 也就是說,在 CustomerType 屬性的級別上標識依賴項,而不是 Order 對象本身。
通過隱式鏈接,Windows Workflow Foundation 為用戶完成大部分所需的鏈接。 因此,用戶不必顯式建立更新模型,通常可以不關心鏈接或對它的需要。 這使復雜規則集的建模更加簡單并且通常為工作流引擎的隱藏功能。
其他兩種驅動鏈接的機制(基于屬性和顯式)是為更復雜和更具體的方案提供的。
(2) 基于屬性
對于在一個規則內調用的方法,更難明確地計算發生的讀/寫。 為了解決此問題,Windows Workflow Foundation 提供三個屬性,可將這些屬性應用到某個方法以指示其操作:
RuleRead
RuleWrite
RuleInvoke
使用 RuleReadAttribute 屬性 (attribute) 對方法進行屬性設置指示該方法讀取所指示的屬性 (property)。 同樣,可以使用 RuleWriteAttribute 屬性 (attribute) 來指示方法將更新給定的字段或屬性 (property)。 假定將隱式節下的前兩個規則重寫為:
Rule 1
IF this.discount > 0
THEN this.total = (1-this.discount) * this.subtotal
Rule 2
IF this.subtotal > 10000
THEN this.SetDiscount(0.05)
然后,可以將 SetDiscount 方法按如下方式進行屬性設置。 這會使引擎能夠標識規則 1 依賴于規則 2,因為使用了折扣字段。
[RuleWrite("discount")]
void SetDiscount(double requestedDiscount)
{
...//Some code that updates the discount field.
}
RuleInvokeAttribute 屬性可以用于指示由鏈接的方法調用導致的依賴項。 例如,假定對規則和方法進行下列修改:
Rule 1
IF this.discount > 0
THEN this.total = (1-this.discount) * this.subtotal
Rule 2
IF this.subtotal > 10000
THEN this.SetDiscountWrapper(0.05)
[RuleInvoke("SetDiscount")]
void SetDiscountWrapper(double requestedDiscount)
{
...
SetDiscount(requestedDiscount);
...
}
[RuleWrite("discount")]
void SetDiscount(double requestedDiscount)
{
}
規則 2 的操作調用 SetDiscountWrapper。 此方法又調用寫入折扣字段的 SetDiscount。 RuleInvokeAttribute 使工作流運行時引擎能夠聲明和檢測到這種間接寫入。
應該認識到,在屬性 (attribute) 路徑中引用的字段或屬性 (property) 指的是與該方法位于同一類上的字段或屬性 (property)。 這不一定是傳遞給 RuleSet 以執行的根對象。 例如,可能會按如下方式對
Order 類進行屬性設置:
public class Order
{
private double discount;
public double Discount
{
get { return discount;}
set { discount = value;}
}
[RuleWrite("Discount")]
void CalculateDiscount(double requestedDiscount, double weighting)
{
... //Some code that updates the discount field.
}
}
然后,可以在工作流中使用此類的實例,如下所示:
public class Workflow1 : SequentialWorkflowActivity
{
private Order discount;
...
}
執行規則 2 會導致重新計算規則 1:
Rule 1
IF this.order.Discount > 5
THEN ...
Rule 2
IF ...
THEN this.order.CalculateDiscount( 5.0, .7)
使用屬性
以下是有關使用屬性的一些補充說明:
1) 可以使用屬性指定如何在方法中使用參數。 例如,通過對以下方法進行屬性 (attribute) 設置,指示此方法修改傳遞的 Order 實例上的 Discount 屬性 (property)。
[RuleWrite("currentOrder/Discount", RuleAttributeTarget.Parameter)]
private void SetDiscount(Order currentOrder, double discount)
{
currentOrder.Discount = discount;
}
2) 在規則屬性中還可以使用通配符。 例如,可以使用 RuleWrite("order/*") 指示此方法修改“order”字段引用的對象上的所有字段。 但是,只能在路徑的末尾使用通配符;像 RuleWrite("*/Discount") 之類的屬性無效。
3) 像 RuleWrite("order") 之類的屬性可以與引用類型一起使用以指示引用已更改,例如,指示變量目前指向其他 Order 實例。 除了測試實例引用本身的所有規則外,使用字段/屬性的所有規則也都假定為受到影響;例如 IF this.order == this.order2。
4) 在未指定方法屬性情況下的默認行為,是假定方法調用在目標對象(即對其調用方法的對象)上不讀取或寫入任何字段/屬性。 此外,假定該方法調用根據 .NET Framework 中定義的關鍵字(ref、out、ByVal、ByRef 等)讀取參數和寫入參數。
(3) 顯式
指示字段/屬性依賴項的最后一種機制是使用 Update 語句。 Update 語句將表示字段或屬性的路徑或表示字段/屬性訪問的表達式作為其參數。例如,可以將以下兩個語句之一鍵入 RuleSet 編輯器中,以創建針對工作流上Customer 實例的 Name 屬性的 Update 語句。
Update("this/customer/Name")
OR
Update(this.customer.Name)
注意:
RuleSet 編輯器始終將更新顯示為 Update("this/customer/Name")。
Update 語句指示規則寫入指示的字段/屬性。 這與在規則中直接設置字段/屬性或使用字段/屬性的 RuleWriteAttribute 調用方法的效果相同。
Update 語句也支持通配符的使用。 例如,可以將以下 Update 語句添加到規則中:
Update("this/customer/*")這會導致對在條件中使用 Customer 實例上的任何屬性的所有規則進行重新計算。 也就是說,將重新計算下面的兩個規則:
IF this.customer.ZipCode == 98052
THEN ...
IF this.customer.CreditScore < 600
THEN ...
通常在大多數情況下,不必對顯式 Update 語句建模;隱式鏈接會提供所需的依賴項分析和鏈接。方法屬性設置支持大多數隱式鏈接無法標識依賴項的一般情況。 一般情況下,通過方法屬性設置來指示依賴項比使用 Update 語句更可取,因為在方法中標識一次依賴項就可以在許多使用該方法的不同規則中使用該依賴項。 此外,在規則編寫者和方法實施者不是同一個人(或者編寫和實施工作在不同的時間進行)的情況下,方法屬性設置使方法編寫者能夠更好地理解代碼,從而能夠標識屬于該方法的依賴項。
但是,在某些情況下,Update 語句是適當的解決方案,例如在將字段/屬性傳遞給您(工作流編寫者)不能控制、因而無法進行屬性設置的類上的方法時。下面的示例說明了這一點。
IF ...
THEN this.customer.UpdateCreditScore(this.currentCreditScore)
Update(this.currentCreditScore)
5正向鏈接控制
正向鏈接是一個非常強大的概念,它使原子規則能夠組合成規則集,而無需定義規則間的依賴性,甚至不必知道這些依賴性。 但是,在某些情況下,規則編寫者可能希望能夠對鏈接行為提供更多控制,尤其是能夠限制發生的鏈接。這使規則建模器能夠做到以下幾點:
· 限制規則的重復執行,從而避免得到不正確的結果。
· 提高性能。
· 防止出現失控循環。
Windows Workflow Foundation 提供了下面的兩個屬性,以使這一級別的控制變得更加輕松:
· RuleSet 上的 ChainingBehavior 屬性。
· 每個 Rule 上的 ReevaluationBehavior 屬性。
兩者的值都可在規則集編輯器中進行設置
ChainingBehavior 屬性
RuleSet 對象上的 ChainingBehavior 屬性可設置為三個可能的值:Full、UpdateOnly 或 None。
· Full 選項為默認值,它提供了到目前為止所述的行為。
· UpdateOnly 選項關閉隱式的、基于屬性的鏈接,并規定鏈接只應對顯式 Update 語句發生。這使您能夠完全控制哪些規則引起重新計算。 通常,使用此選項可以避免導致規則過度(甚至是失控)重復執行的循環依賴性,或者通過消除為提供 RuleSet 的功能完整性所不需要的規則重新計算來提高性能。
· 最后一個選項為 None。 此選項使引擎以嚴格線性方式對規則進行計算。 每個規則都將按照優先級順序分別只計算一次。優先級較高的規則可能影響優先級較低的規則,但反之則不然,因為不會發生鏈接。 因此,在使用此選項時,需要顯式分配優先級,除非規則之間不存在依賴性。
ReevaluationBehavior 屬性
Rule 對象上的 ReevaluationBehavior 屬性有兩個可能的值:Always 和 Never。
· Always 為默認值,它提供了前面討論過的行為,即,總是根據其他規則的操作所引起的鏈接重新計算規則。
· Never 顧名思義就是關閉重新計算。 規則計算一次,但如果該規則先前已執行了任何操作,則不進行重新計算。換言之,如果先前計算過該規則,并因此執行了其 Then 或 Else 操作,則不會重新計算該規則。 但是,執行 Then 或 Else 操作中的空操作集合并不表示規則已經執行。
通常,此屬性在規則級別使用,目的是防止由規則對其自身操作的依賴性或對其他規則的依賴性造成的無限循環。例如,下面的規則會產生其自身的無限循環,并且無需進行重新計算即能滿足該規則的功能要求:
IF this.shippingCharge < 2.5 AND this.orderValue > 100
THEN this.shippingCharge = 0
另外,如果打算重新計算該規則,但只在 OrderValue 字段更改時重新計算,則用戶可以將 RuleSet 上的鏈接行為設置為只對顯式 Update 語句進行鏈接(然后將這些 Update 語句添加到相關的規則操作)。 當然,用戶可能已經向此規則添加了附加謂詞,以檢查 ShippingCost 的值是否尚不為 0。但是,鏈接控制使用戶無需根據計算過程的詳細信息來定義其規則,而可以根據其業務要求來定義規則。
Halt 函數
作為最后一項控制,可以將 Halt 函數作為規則操作進行添加(在編輯器中的 Then 或 Else 操作框中鍵入“Halt”)。 這會立即停止 RuleSet 執行,并將控制返回給調用代碼。 當然,此函數的用處并不局限于鏈接控制方案。 例如,一個具有特定功能目標的 RuleSet 可以使用 Halt 函數在達到目標后立即中斷執行。
6以編程方式運行 RuleSet
除了使用 PolicyActivity 活動運行 RuleSets 以外,您還可以在 RuleSet 中以編程方式運行和計算規則。 例如,假設您要在活動代碼中依據活動(工作流或任何其他活動類型)執行 RuleSet。 下面的代碼演示如何執行此操作:
RuleValidation validation = new RuleValidation(typeof(customActivity),null);
// "this" in the call below refers to the activity instance.
RuleExecution execution = new RuleExecution(validation, this);
customRuleSet.Execute(execution);
一般情況下,如果您在工作流中使用規則,那么,構造 RuleExecution 實例時還要傳遞 ActivityExecutionContext。 提供上下文的主要優點是:您可以將規則執行信息發送到主機的跟蹤提供程序。
也可以使用 RuleEngine 對象直接執行 RuleSet 對象。 下面的代碼演示如何執行此操作。
RuleValidation validation = new RuleValidation(typeof(customActivity),null);
// "this" in the call below refers to the activity instance.
RuleEngine engine = new RuleEngine(customRuleSet, validation);
engine.Execute(this);
請注意,如果只想根據給定類型(例如,如果它包含規則中引用的所有成員)驗證規則集,則可以按如下所示進行表示:
bool result = myRuleSet.Validate(validation);
如果 RuleSet 有效,則 Validate 方法調用的結果為 true。 RuleValidation 實例具有一個存在驗證錯誤的 Errors 屬性。
注意:
您也可以在工作流外使用 RuleSets。 對于 RuleSet,可根據任何 .NET Framework 類型進行編寫。
7跟蹤 RuleSet 信息
執行 RuleSet 時,將向在宿主上配置的跟蹤服務發送跟蹤事件,這些宿主已通過向其跟蹤配置文件添加 UserTrackPoint 注冊了這些事件。 將發送 RuleActionTrackingEvent,其中提供了已計算的規則的名稱以及條件計算結果 (true/false)。
通過跟蹤活動執行情況,可以隱式地跟蹤活動上的規則條件的計算結果。
啟用跟蹤
通過向應用程序配置文件中添加下面的代碼,可以將其他的 RuleSet 計算信息發送給日志文件。
<configuration>
<system.diagnostics>
<switches>
<add name="System.Workflow.Activities.Rules" value="Information"/>
</switches>
</system.diagnostics>
</configuration>
將下列信息發送給日志文件:
· 規則集執行(信息)
· 條件計算結果(信息)
· 條件依賴項信息(詳細)
· 操作副作用信息(詳細)
· 鏈接關系(詳細)
· 條件計算(詳細)
· 操作執行(詳細)
所有跟蹤消息都是在指定的級別定義的,因此應根據需要查看的消息類型在配置文件中指定“信息”或“詳細”級別。
8聲明性 RuleSet
除了使用規則編輯器創建基于標記的規則集之外,還可以使用 RuleDefinitions 類以編程方式創建規則。此類具有兩個名為 Conditions 和 RuleSets 的集合屬性。
下面的示例演示如何以編程方式創建 RuleSet。 在此示例中,首先創建一個 RuleSet 對象,然后向其添加規則。 之后,創建引用表達式,以便將規則與用來實現 BuildRuleSet 方法的類中所顯示的實例數據相關聯。 discount、orderValue 和 customerType 引用是在該類中定義的字段。 下一步是使用 System.CodeDom 命名空間中的對象創建住戶折扣規則。要創建的規則將檢查定單值是否大于 500 且客戶類型是否為住戶。 如果條件為 true,則適用的折扣為 5%。 接下來,使用不同的值創建類似規則,指示如果客戶為商業客戶類型時所適用的折扣。這兩個規則都將添加到初始 RuleSet 中。
private RuleSet BuildRuleSet()
{
RuleSet discountRuleSet = new RuleSet("DiscountRuleSet");
// Define property and activity reference expressions.
CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression();
CodeFieldReferenceExpression discountRef = new CodeFieldReferenceExpression(thisRef, "discount");
CodeFieldReferenceExpression orderValueRef = new CodeFieldReferenceExpression(thisRef, "orderValue");
CodeFieldReferenceExpression customerTypeRef = new CodeFieldReferenceExpression(thisRef, "customerType");
CodeTypeReferenceExpression customerEnumRef = new CodeTypeReferenceExpression(typeof(CustomerType));
// Add the residential discount rule.
// IF OrderValue > 500 AND CustomerType = Residential
// THEN Discount = 5%
Rule resDiscountRule = new Rule("ResidentialDiscountRule");
discountRuleSet.Rules.Add(resDiscountRule);
// Define the first predicate test: OrderValue > 500.
CodeBinaryOperatorExpression resOrderValueTest = new CodeBinaryOperatorExpression();
resOrderValueTest.Left = orderValueRef;
resOrderValueTest.Operator = CodeBinaryOperatorType.GreaterThan;
resOrderValueTest.Right = new CodePrimitiveExpression(500);
// Define the second predicate test: CustomerType = Residential.
CodeBinaryOperatorExpression resCustomerTypeTest = new CodeBinaryOperatorExpression();
resCustomerTypeTest.Left = customerTypeRef;
resCustomerTypeTest.Operator = CodeBinaryOperatorType.ValueEquality;
resCustomerTypeTest.Right = new CodeFieldReferenceExpression(customerEnumRef, "Residential");
// Join the two predicates into a single condition.
CodeBinaryOperatorExpression resCondition = new CodeBinaryOperatorExpression();
resCondition.Left = resOrderValueTest;
resCondition.Operator = CodeBinaryOperatorType.BooleanAnd;
resCondition.Right = resCustomerTypeTest;
resDiscountRule.Condition = new RuleExpressionCondition(resCondition);
// Add the rule action: Discount = 5%.
CodeAssignStatement resDiscountAction = new CodeAssignStatement(discountRef, new CodePrimitiveExpression(5));
resDiscountRule.ThenActions.Add(new RuleStatementAction(resDiscountAction));
// Add the business discount rule.
// IF OrderValue > 10000 AND CustomerType = Business
// THEN Discount = 10%
Rule busDiscountRule = new Rule("BusinessDiscountRule");
discountRuleSet.Rules.Add(busDiscountRule);
CodeBinaryOperatorExpression busOrderValueTest = new CodeBinaryOperatorExpression();
busOrderValueTest.Left = orderValueRef;
busOrderValueTest.Operator = CodeBinaryOperatorType.GreaterThan;
busOrderValueTest.Right = new CodePrimitiveExpression(10000);
CodeBinaryOperatorExpression busCustomerTypeTest = new CodeBinaryOperatorExpression();
busCustomerTypeTest.Left = customerTypeRef;
busCustomerTypeTest.Operator = CodeBinaryOperatorType.ValueEquality;
busCustomerTypeTest.Right = new CodeFieldReferenceExpression(customerEnumRef, "Business");
CodeBinaryOperatorExpression busCondition = new CodeBinaryOperatorExpression();
busCondition.Left = busOrderValueTest;
busCondition.Operator = CodeBinaryOperatorType.BooleanAnd;
busCondition.Right = busCustomerTypeTest;
busDiscountRule.Condition = new RuleExpressionCondition(busCondition);
CodeAssignStatement busDiscountAction = new CodeAssignStatement(discountRef, new CodePrimitiveExpression(10));
busDiscountRule.ThenActions.Add(new RuleStatementAction(busDiscountAction));
return discountRuleSet;
}
若要創建一個 RuleDefinitions 對象并將它與某個工作流相關聯,請按如下方式添加前面所顯示的 RuleSet:
RuleDefinitions definitions = new RuleDefinitions();
definitions.RuleSets.Add(BuildRuleSet());
this.SetValue(RuleDefinitions.RuleDefinitionsProperty, definitions);
若要將 RuleSet 與 PolicyActivity 活動一起使用,請創建一個將 RuleSet 的名稱用作構造函數參數的新 RuleSetReference,如下所示:
private void InitializeComponent()
{
this.CanModifyActivities = true;
// Create the Policy activity.
this.discountPolicy = new PolicyActivity();
this.discountPolicy.Name = "advancedDiscountPolicy";
this.discountPolicy.RuleSetReference = new RuleSetReference("DiscountRuleSet");
// Define the workflow.
this.Activities.Add(this.discountPolicy);
this.Name = "DiscountPolicyWorkflow";
this.CanModifyActivities = false;
}
private PolicyActivity discountPolicy;
使用下面的類似方法可以將規則用作活動條件:
// This code is called by the workflow constructor.
CodeBinaryOperatorExpression check = new CodeBinaryOperatorExpression();
check.Left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "orderValue");
check.Operator = CodeBinaryOperatorType.LessThan;
check.Right = new CodePrimitiveExpression(10000);
RuleDefinitions definitions = new RuleDefinitions();
definitions.Conditions.Add(new RuleExpressionCondition("Condition1", check));
this.SetValue(RuleDefinitions.RuleDefinitionsProperty, definitions);
// This code is called in the InitializeComponent method to populate the
// condition on an IfElseBranch activity.
RuleConditionReference condition1 = new RuleConditionReference();
condition1.ConditionName = "Condition1";
ifElseBranch1.Condition = condition1;
9規則的編程注意事項
規則具有很強的可擴展性,并提供了許多功能;但是,關于規則編程,也有一些值得注意的方面。具體如下:
· 在規則操作內部更新的 struct 屬性值不會在該規則之外反映出來。這是因為 struct 值是按值復制的,規則操作會修改副本,但不會修改 struct 中的原始值。
· 當將 decimal、double 或 float 數據類型強制轉換為 int 數據類型時,值會向上舍入。這一行為與 C# 中的行為不同,在 C# 中,值會截斷,而不是舍入。對值調用 Math.Ceiling 或 Math.Floor 將有效地截斷值。
· 除非在單獨的項目中定義泛型類型,并從工作流項目內部調用它,否則不支持在設計時使用泛型類型。
posted on 2008-12-10 09:14 mjgforever 閱讀(2834) 評論(0) 收藏 舉報
浙公網安備 33010602011771號