评估字符串中定义的一组规则

时间:2011-10-03 16:33:06

标签: c#

我创建了一个用函数/响应格式创建一个简单字符串的系统,例如:

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

其中Check是函数的名称,Value是参数,ShowImage是响应函数的名称,@是条目参数(结果为上一个功能)。管道分裂另一个功能/响应对,如果第一个Check('Value')功能一旦“检查”不满意就会触发(例如,如果参数未完成Check条件,则该功能无效,因此响应第一个函数/响应对中的部分未执行,因此系统会继续尝试等待执行正确响应的函数。

应用程序的工作方式是评估每个规则(类似于JavaScript eval函数)并根据函数结果采取适当的操作。

乍一看,它看起来很复杂,因为首先我需要将字符串转换为实际处理条件的正确的C#函数。因此,根据函数结果,决定执行响应函数的位置。

此外:这只是一个类似的例子,因为有*这样的函数表示类似:“任何条件都是真的”几乎所有情况下这个函数都是链中的最后一个(默认函数) )。

这是我的问题,我无法意识到解决这个问题的最简单方法是什么。 也许是一连串的代表? Lambda表达式?匿名存储到结构中......

你能告诉我你的措施/建议吗?从哪里开始?

3 个答案:

答案 0 :(得分:0)

看起来你想要一个符合.NET TryParse()方法的模式。在这种情况下,您可以修改check方法以使out参数成为值(在您的示例中由@表示)。

int result;

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

答案 1 :(得分: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;
        }
    }
}

上面使用的“结果”将具有如下界面:

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 })
    );
}

或多或少,你的程序的骨架。作为练习,您应该能够自己填写缺失的部分。如果您遇到问题,我可以稍后更新答案。

GetMethodAndParams方法应该将输入字符串拆分为Tuple(或您的自定义类),其中包含方法名称及其参数作为纯字符串。 TesterExecutor类也可以轻松实现。

答案 2 :(得分:0)

最后,我回到这里发布我几周前为解决这种情况所做的事情。 这很容易。

Regex类提供的选项很少,其中一个是“Explicit 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);
}

当然,失去了动作部分所以我用专门的Struct改进了Dictionary的东西,它可以处理函数和值作为决策的来源。

感谢所有人。编