System.Linq.Dynamic.DynamicExpression使用方法解析表达式 [英] System.Linq.Dynamic.DynamicExpression parsing expressions with methods

查看:234
本文介绍了System.Linq.Dynamic.DynamicExpression使用方法解析表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要构建一个系统,在该系统中我有许多存储在文件中的表达式.这些表达式将被读入程序,编译为linq表达式,并作为多个对象的函数进行评估.但是,这些表达式将包含对代码中某些函数的引用(即它们将不仅仅由基本的C#运算符组成).

I need to build a system where I have a number of expressions that are stored in a file. These expressions would be read into the program, compiled into linq expressions and evaluated as functions on a number of objects. However, these expressions would contain references to some functions in the code (i.e. they would not be made of just basic C# operators).

我正在尝试使用System.Linq.Dynamic中的DynamicExpression,它几乎可以工作,除了无法识别我的代码中的功能.基本上,当我在下面有以下代码时:

I'm trying to use DynamicExpression from System.Linq.Dynamic and it almost works, except that my functions from the code are not recognized. Basically, when I have this code below:

public class GeoObj
{
    public int layer;
    public Polygon poly;
}

class Program
{
    public static bool ComplicatedMethod(GeoObj x, GeoObj y)
    {
        bool result = // some quite complicated computation on x and y, say a polygon intersection test
        return result;
    }

    static void Main(string[] args)
    {
        GeoObj o1 = new GeoObj(); // here set o1 fields
        GeoObj o2 = new GeoObj(); // here set o2 fields

        string sExpr = @"(x.layer == y.layer) && (ComplicatedMethod(x,y))";

        var xparam = Expression.Parameter(typeof(GeoObj), "x");
        var yparam = Expression.Parameter(typeof(GeoObj), "y");

        Expression<Func<GeoObj, GeoObj, bool>> expr = (Expression<Func<GeoObj, GeoObj, bool>>)System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { xparam, yparam }, typeof(bool), sExpr);

        var del2 = expr.Compile();
        Console.WriteLine(del2(o1, o2));
    }
}

(当然,在最终版本中,将从文本文件中读取sExpr,但这只是一个示例.)

(Of course, in the final version, sExpr would be read from a text file, but this was just as an example.)

代码在ParseLambda处引发异常,指出"ComplicatedFunction"未知.我可以看到ParseLambda如何不知道"ComplicatedFunction",因为它不知道在哪个程序集中使用它.

The code throws an exception at ParseLambda, stating that "ComplicatedFunction" is not known. I can see how ParseLambda would not know about "ComplicatedFunction" because it does not know in which assembly it's used.

有没有办法将该字符串编译为实际表达式?如果我使用这样的硬编码在代码中创建表达式:

Is there a way to compile that string into an actual expression? If I create the expression in my code using something hard-coded like this:

Expression<Func<GeoObj, GeoObj, bool>> expr = (x, y) => (x.layer == y.layer) && ComplicatedFunction(x,y));

它可以按我的预期工作,但是我无法预期所有可能的表达式.

it works as I intended, but I cannot anticipate all possible expressions.

如果不可能的话,我想第二件事是将字符串表达式解析为一个解析树,并从该树中创建该表达式.由于将只使用少数几个函数(例如"ComplicatedFunction"),因此它看起来是可行的.从这样的表达式创建语法树的最佳方法/最佳代码是什么?我需要一种在不知道符号的情况下也不会引发异常的东西(例如"ComplicatedFunction"),并使我可以轻松地解析树以构建表达式.

If it's not possible, I suppose the next best thing is to parse the string expressions into a parse tree, and create the expression from that tree. Since there are only a few functions (like "ComplicatedFunction") that will be used, it looks doable. What is the best way/best code to create the syntax tree from such an expression? I would need something that would not throw exceptions when a symbol is not known (like "ComplicatedFunction") and would make it easy for me to to parse the tree to build the expression.

谢谢.

--------------------更新-------------------------- -------

-------------------- UPDATE ---------------------------------

@ pil0t的答案使我走上了正确的道路.基本上,您必须下载Dynamic Linq的原始源文件并进行两次修改.

@pil0t 's answer put me on the right track to solving this. Basically, you have to download the original source file for Dynamic Linq and make two modifications.

寻找:

static readonly Type[] predefinedTypes = {

并删除"readonly"关键字(以便可以对其进行修改).

and remove the 'readonly' keyword (so it can be modified).

然后,将以下函数添加到ExpressionParser类:

Then, add the following function to the ExpressionParser class:

    public static void AddPredefinedType(Type type)
    {
        predefinedTypes = predefinedTypes.Union(new[] { type }).ToArray();
        keywords = ExpressionParser.CreateKeywords();
    }

您可以像这样使用新功能:

You can use the new function like this:

using System.Linq.Dynamic;
...
ExpressionParser.AddPredefinedType(typeof(GeoObj));

请注意有关表达式语法的注意事项.新添加的函数将使您可以访问类"GeoObj"(或您使用的任何类)的方法,并且只能访问这些方法.这意味着您必须按如下所示修改表达式:

One note about the syntax for the expressions though. The newly added function will give you access to the methods of the class 'GeoObj' (or whatever class you use), and only to those. This means that you'll have to modify the expression as follows:

class GeoObj {
    public bool field1;
    public bool method1() { /* return something */ }
    public static ComplicatedMethod(GeoObj o1, GeoObj o2) { ... }
}
...
string myExpr = @"x.field1 && y.method1() && GeoObj.ComplicatedMethod(x,y)";

换句话说,您需要使用的所有功能都需要在类内移动,就像@Shlomo所暗示的那样.我本来希望使用更简洁的表示法(例如,使用"ComplicatedMethod(x,y)"代替"GeoObj.ComplicatedMethod(x,y)",或者使用类似Method1(x)代替x.Method1()),但是在这一点上,这些大多是审美偏好.此外,由于可以使用的此类方法数量很少,因此表达式可以在内部进行重写,以从类似函数调用的表达式转换为方法调用.

In other words, all functions that you need to use need to be moved inside the class, like @Shlomo hinted at. I would've liked a cleaner notation (e.g. use "ComplicatedMethod(x,y)" instead of "GeoObj.ComplicatedMethod(x,y)", or have something like Method1(x) instead of x.Method1()), but these are mostly aesthetic preferences at this point. Besides, since the number of such methods that can be used is small, expressions can be rewritten internally to go from function-call-like-expressions to method calls.

感谢大家为我指出正确的方向.

Thanks everyone for pointing me in the right direction.

推荐答案

我通过使用

public class Foo
{
...
        public static void AddPredefinedType(Type type)
        {
            ExpressionParser.predefinedTypes = ExpressionParser.predefinedTypes.Union(new[] { type }).ToArray();
            ExpressionParser.CreateKeywords();
        }
}

在此之后,您可以使用

Foo.AddPredefinedType(typeof(Program));

所有程序中的方法都将可用

and all methods from Program will be available

这篇关于System.Linq.Dynamic.DynamicExpression使用方法解析表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆