计算在字符串中定义的一组规则
本文关键字:一组 规则 字符串 定义 计算 | 更新日期: 2023-09-27 18:10:24
我创建了一个系统,它创建了一个函数/响应格式的简单字符串,例如:
Check('Value'):ShowImage(@)|Check('Value'):OtherFunction(@)....and so on
其中Check
为函数名,Value
为参数,ShowImage
为响应函数名,@
为入口参数(前一个函数的结果)。管道分割另一个函数/响应对,如果第一个Check('Value')
函数被"检查"后不满足(例如,如果参数没有完成Check
条件,则函数无效,因此第一个函数/响应对中的响应部分没有执行,因此系统继续尝试函数等待找到执行正确响应的函数)。
应用程序的工作方式应该是评估每个规则(类似于JavaScript的eval函数),并根据函数的结果采取适当的操作。
乍一看,它看起来很复杂,因为首先我需要将字符串强制转换为实际处理条件的c#函数。因此,根据函数的结果,决定在哪里执行我的Response函数。
进一步:这只是一个很好的例子,因为有函数*
表示:"任何条件都为真",在几乎所有情况下,这个函数都是链中的最后一个(默认函数)。
根据您想要的可扩展性级别,我认为最具可扩展性的方法是在解析了输入字符串之后使用反射来获取方法引用。
你可以先把你的问题分成更小的子问题。
假设你的目标是这样的:
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;
}
}
}
上面使用的"result"会有这样的接口:
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(或您的自定义类),其中包含方法名称及其参数为普通字符串。Tester
和Executor
类也可以简单地实现。
看起来您想要一个遵循. net TryParse()
方法的模式。在这种情况下,您将修改您的检查方法,使其具有一个out参数,即值(在您的示例中由@
表示)。
int result;
if(Check('Value', out result))
ShowImage(result);
else(Check('Value2', out result))
OtherFunction(result);
最后我回到这里来发布我几周前解决这个问题的方法。这很容易。
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);
}
当然,有丢失的操作部分,所以我已经改进了字典的东西与一个专门的结构,可以处理函数和值作为决策的来源。
谢谢大家。艾德。