我正在嘗試編寫一些代碼來匹配基于模式的字符串:模式:“狗和(貓或山羊)”測試字符串:“doggoat” 結果:true測試字符串:“dogfrog” 結果:假我正在嘗試使用 Sprache 編寫解析器,其中大部分邏輯由 Corey對類似問題的出色回答提供。我快到了,但是運行代碼時出現異常:System.Func'沒有為類型2[System.String,System.Boolean]' 和 ''System.Func`2[System.String,System.Boolean]'定義二元運算符 AndAlso 。我知道這意味著我需要將表達式樹節點處的 lambda 表達式與邏輯運算符結合起來,我根據此處另一個問題的答案嘗試使用 ExpressionVisitor 。但是,程序在執行 ExpressionVisitor 之前崩潰 - 似乎首先執行 Parse 命令,但我不太明白為什么(可能是因為 Sprache.Parse.Select 語句不強制執行 lambda?) ,或者如何強制它先被執行。示例代碼如下(為了簡潔起見,我刪除了所有運算符,但“和”除外,從Corey 的模板中重新引入它們是微不足道的。必須從 NuGet 添加 Sprache 才能編譯代碼。class Program{ static void Main(string[] args) { var patternString = "dog and cat"; var strTest = "dog cat"; var strTest2 = "dog frog"; var conditionTest = ConditionParser.ParseCondition(patternString); var fnTest = conditionTest.Compile(); bool res1 = fnTest(strTest); //true bool res2 = fnTest(strTest2); //false }}public static class ConditionParser{ static ParameterExpression Param = Expression.Parameter(typeof(string), "_"); public static Expression<Func<string, bool>> ParseCondition(string text) { return Lambda.Parse(text); } private static Parser<Expression<Func<string, bool>>> Lambda { get { var reduced = AndTerm.End().Select(delegate (Expression body) { var replacer = new ParameterReplacer(Param); return Expression.Lambda<Func<string, bool>>((BinaryExpression)replacer.Visit(body), Param); }); return reduced; } } static Parser<Expression> AndTerm => Parse.ChainOperator(OpAnd, StringMatch, Expression.MakeBinary); // Other operators (or, not etc.) can be chained here, between AndTerm and StringMatch static Parser<ExpressionType> OpAnd = MakeOperator("and", ExpressionType.AndAlso); private static Parser<Expression> StringMatch => Parse.Letter.AtLeastOnce() .Text().Token() .Select(value => StringContains(value));
1 回答

犯罪嫌疑人X
TA貢獻2080條經驗 獲得超4個贊
您的代碼存在幾個問題,但導致異常的主要問題是StringContains
返回 lambda 表達式的方法。并且Expression.AndAlso
(以及大多數Expression
方法)基于簡單的非 lambda 表達式(或 lambda 表達式主體)。解析代碼的整個想法是識別和組合簡單的表達式,并從結果表達式中生成單個 lambda 表達式。
要解決原始問題,該StringContains
方法應直接返回MethodCall
表達式而不是 lambda 表達式。
同一StringContains
方法中的第二個問題是將參數反轉為string.Contains
. 它基本上是這樣做token.Contains(parameter)
的,而根據預期結果它應該做相反的事情。
整個方法(使用另一個方便的Expression.Call
重載)可以簡化為
static Expression StringContains(string subString) => Expression.Call(Param, "Contains", Type.EmptyTypes, Expression.Constant(subString));
現在一切都應該按預期工作。
但是,由于ConditionParser
該類使用單個ParameterExpression
實例,然后用于構建 lambda 表達式,因此不需要ParameterReplacer
,因此Lambda
方法(屬性)可以簡化為
private static Parser<Expression<Func<string, bool>>> Lambda => AndTerm.End().Select(body => Expression.Lambda<Func<string, bool>>(body, Param));
- 1 回答
- 0 關注
- 99 瀏覽
添加回答
舉報
0/150
提交
取消