2011-10-03 48 views
1

定義一組規則我提出,帶有功能/響應格式創建了一個簡單的字符串的系統中,例如:評價在字符串

Check('Value'):ShowImage(@)|Check('Value'):OtherFunction(@)....and so on 

Check是一個函數的名稱,Value是參數, ShowImage是響應函數的名稱,@是入口參數(前一個函數的結果)。管道拆分另一個功能/響應對,火災如果第一Check('Value')函數一次「選中」沒有滿足(比方說,如果該參數沒有被完成的Check條件的功能是在所述第一功能/響應對無效,並因此響應部沒有執行,所以系統繼續嘗試函數等待找到執行正確響應的函數)。

應用程序應該工作的方式是評估每個規則(類似於一個JavaScript eval函數),並採取基於函數的結果採取適當的行動。

乍一看,看起來比較複雜,因爲首先我需要將字符串轉換爲將實際處理條件的權利真正的C#功能。因此,根據函數結果,決定指向何處執行我的響應函數。

此外:這僅僅是一個例子,因爲有*這樣的函數,它們表示類似於「任何條件爲真」的函數,幾乎所有情況下該函數都是鏈中的最後一個(默認函數)。

這是我的問題,我不能體會到什麼是應對這一問題的最簡單的方法。 也許是一連串的代表? Lambda表達式?匿名存儲在一個結構...

你能給我你的措施/建議嗎?從哪兒開始?

+1

這並不完全清楚你的問題是什麼。如果我說得對,現在你有這個「字符串」代表一組規則和動作,應該使用C#解析並執行它?它需要看起來像這樣嗎?或者這只是一個建議? – Groo

+0

你懂了!這個「字符串」是一組規則。然後將每一個解析爲一個C#函數,然後進行求值,如果函數找到一個「out」參數Check條件(想象我們正在「檢查」一個字典),那麼它的引用就是響應的參數功能。 –

+0

我一直在使用NCalc進行一個不同但相當相似的項目。 NCalc允許您使用「自定義函數」,然後您可以捕捉它,但最終會評估爲數學表達式,因此您的規則集將不得不進行修改以支持該規則。無論如何,它有點像Eval函數,所以它可能對你有所幫助,所以你不必做很多解析工作,並可以在你的變量中包含數學公式。然後你可以像使用它(http://ncalc.codeplex.com/) – deepee1

回答

0

根據你想擁有可擴展的水平,我會說,最可擴展的方式是使用反射來獲取方法的引用,你已經解析輸入字符串之後。

您可以通過拆分您的問題分成更小的子問題開始。

比方說,你的目標是這樣的事情:

static void Main(string[] args) 
{ 
    string rules = 
     "Check(Morning):Say(Good morning)|" + 
     "Check(Afternoon):Say(Good afternoon)|" + 
     "Check(Evening):Say(Good night)"; 

    // next, you need some **object instances** which will 
    // provide a context for your "test" and "action" methods. 
    // you don't want to use static methods if you 
    // went through the pain of defining such an architecture! 

    // let's say that a "Tester" object has a "Check" method, 
    // and an "Executor" object has a "Say" method: 

    var tester = new Tester("Afternoon"); 
    var executor = new Executor(); 

    // since I suck at regular expressions, 
    // I am using plain string methods to split 
    // the expression into tokens. You might want 
    // to add some validation 

    foreach (var rule in rules.Split('|')) 
    { 
     var result = Parse(rule, tester, executor); 
     if (result.TestPassed) 
     { 
      result.Execute(); 
      break; 
     } 
    } 
} 

A「結果」,因爲它的上面使用,那麼就會有一個這樣的接口:

public interface IResult 
{ 
    // returns true if a test is fulfilled 
    bool TestPassed { get; } 

    // executes the related action 
    void Execute(); 
} 

而且,如果你想將實際行爲委託給某些未知的方法,實施它的合理方式將如下所示:

public class Result : IResult 
{ 
    #region IResult Members 

    private readonly Func<bool> _testMethod; 
    public bool TestPassed 
    { 
     get { return _testMethod(); } 
    } 

    private readonly Action _actionMethod; 
    public void Execute() 
    { 
     _actionMethod(); 
    } 

    #endregion 

    public Result(Func<bool> testMethod, Action actionMethod) 
    { 
     _testMethod = testMethod; 
     _actionMethod = actionMethod; 
    } 
} 

剩下的就是用一些反射來獲取實際的方法,你的字符串:

private static IResult Parse(string rule, object tester, object executor) 
{ 
    // split into test/action 
    var tokens = rule.Split(':'); 

    // extract the method/parameter part for each expression 
    var test = GetMethodAndParams(tokens[0]); 
    var action = GetMethodAndParams(tokens[1]); 

    // use reflection to find actual methods 
    var testMethod = tester.GetType().GetMethod(test.Method); 
    var actionMethod = executor.GetType().GetMethod(action.Method); 

    // return delegates which will simply invoke these methods 
    return new Result 
    (
     () => (bool)testMethod.Invoke(tester, new object[] { test.Param }), 
     () => actionMethod.Invoke(executor, new object[] { action.Param }) 
    ); 
} 

也就是說,或多或少,你的程序的骨架。作爲練習,您應該能夠自己填寫缺失的部分。如果您有問題,我可以稍後更新答案。

A GetMethodAndParams方法應該將輸入字符串拆分成一個包含方法名稱和它的參數爲純字符串的元組(或您的自定義類)。 TesterExecutor類也可以平凡地實現。

+0

Excelent advise!,即使我做了那樣的事情。謝謝 –

0

它看起來像你想沿着.NET TryParse()方法的線的圖案。在這種情況下,您可以修改您的檢查方法,使其輸出參數爲值(在您的示例中由@表示)。

int result; 

if(Check('Value', out result)) 
    ShowImage(result); 
else(Check('Value2', out result)) 
    OtherFunction(result); 
+0

所以......但我相信有更好的基礎設施來解決這種情況,我想在一個代表鏈中,但我不知道該怎麼做...... –

0

最後,我回到這裏發佈我幾星期前爲解決這種情況所做的工作。 很簡單。

Regex類提供幾個選項,其中的一個是「顯式Catpure」,與以下形式的所有流(?)可以作爲強類型的參數來處理,這樣,如果指定的基團「IsNotEmptyorNull」,那麼功能是本並且可以使用Enum.Parse(「」)形式進行強制轉換。

Snipet:

Regex rx = new Regex(@"(?<function>Check|BooleanOp)\('(?<param>[\w]+)'\){1}:(?<action>[\w]+){1}", RegexOptions.ExplicitCapture); 

Match m; 
Dictionary<FunctionArray, String> actions = new Dictionary<FunctionArray, String>(); 

if((m=rx.Match(strStream)).Success) 
{ 
    actions.Add((FunctionArray)Enum.Parse(typeof(FunctionArray), m.Groups["function"].value, true), m.Groups["param"].value); 
} 

當然,也有失去了行動的一部分,所以我已經改善了字典的東西有專門的結構,可以處理功能和價值作爲決策回吐源。

感謝所有。埃德。