标签: expression-trees

使用ExpressionVisitor获取所有"where"调用

我有一个查询,像这样:

var query = from sessions in dataSet
                    where (names.Contains(sessions.Username))
                    where (sessions.Login.TimeOfAction == dt)                    
                    select new {    sessions.Username, 
                                    sessions.Login, 
                                    sessions.Logout, sessions.Duration };
Run Code Online (Sandbox Code Playgroud)

我想实现一个ExpressionVisitor来提取where子句作为Lambda,但到目前为止只能使用一个名为'InnermostWhereFinder'的类来获得第一个,该类来自TerraServer Web服务的自定义查询提供程序上的MSDN教程.

它是:

internal class InnermostWhereFinder : ExpressionVisitor
    {
        private MethodCallExpression innermostWhereExpression;

        public MethodCallExpression GetInnermostWhere(Expression expression)
        {
            Visit(expression); 
            return innermostWhereExpression;
        }

        protected override Expression VisitMethodCall(MethodCallExpression expression)
        {
            if (expression.Method.Name == "Where")
                innermostWhereExpression = expression;

            Visit(expression.Arguments[0]);

            return expression;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我曾经尝试过大量调整这个类来返回两个没有成功的子句.找不到任何关于此的好文档,任何人都可以帮忙吗?我认为这最终需要产生多个可以使用的LambdaExpression对象.

c# linq lambda iqueryable expression-trees

3
推荐指数
1
解决办法
3376
查看次数

如何为表达式树传递默认参数?

假设我有以下功能

Dal.Person.GetAllByAge<T>(int iAge, Expression<Func<Person, T>> OrderBy)  
Run Code Online (Sandbox Code Playgroud)

我想为表达式传递一个默认参数,如 OrderBy = e=>e.ID,
以便如果未定义此参数,则默认值是按 id 排序。
这怎么可能?

c# expression-trees default-parameters

3
推荐指数
1
解决办法
1211
查看次数

分析树或表达式树

我正在做一个命令行计算器,所以我需要解析表达式.

calc 2*(3+4)*5
Run Code Online (Sandbox Code Playgroud)

我已完成扫描仪步骤,返回令牌的数组.现在我正处于解析器步骤.但是我不清楚如何做一个解析器/表达式树.

这就是我到目前为止所做的一切:

NODE* create_node(TOKEN* t) {
    NODE* n = (NODE*)malloc(sizeof(NODE));
    n->t = t;
    n->l = n->r = 0;
    return n;
}

void insert_node(NODE** top, NODE** n) {
    if (!*top) {
        *top = *n;
        return;
    }

    if (!(*top)->l) insert_node(&(*top)->l, n);
    else
    if (!(*top)->r) insert_node(&(*top)->r, n);
    else
        insert_node(&(*top)->l, n);
}
Run Code Online (Sandbox Code Playgroud)

然后我传递令牌数组,如:

while (*tokens != 0) {
    NODE* n = create_node(*tokens++);
    insert_node(&root, &n);
}
Run Code Online (Sandbox Code Playgroud)

你可以看到我的树只向左抬起.我不知道如何通过顶部的操作员和数字作为叶子(包括运算符优先顺序)进行排序.

我会很感激启发,也喜欢编程(代码)术语.

c parsing expression-trees

3
推荐指数
1
解决办法
4924
查看次数

转换Expression.Property结果

如何Expression动态创建树时创建强制转换?

问题是,我有一个类型的属性string:

public class Test
{
    public string Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想一般创建一个强类型的lambda表达式,表示一个委托,它返回一个object而不是a string(Expression<Func<T, object>>).

现在我这样做:

private static Expression<Func<T, object>> CreateIdQuery()
{
    Type type = typeof(T);
    PropertyInfo idProperty = type.GetProperty("Id");
    ParameterExpression lambdaParam = Expression.Parameter(type, "x");
    MemberExpression body = Expression.Property(lambdaParam, idProperty);
    LambdaExpression expr = Expression.Lambda(body, lambdaParam);
    return (Expression<Func<T, object>>)expr;
}
Run Code Online (Sandbox Code Playgroud)

但它在最后一行引发异常(我无法Expression<Func<Test, string>>转换Expression<Func<Test, object>>).

我如何施放表达式的主体(我假设该MemberExpression部分需要被投入一个object)?

c# reflection expression-trees

3
推荐指数
1
解决办法
1434
查看次数

在表达式树中,如何使用需要与结果进行比较的表达式,例如.指数?

我知道怎么做:

    Expression body = Expression.Call(selector.Body, "Contains", null,
        Expression.Constant("cats", typeof(string)));
Run Code Online (Sandbox Code Playgroud)

由于'contains'返回true/false,因此没有问题.

但是,我如何进行IndexOf并查看结果是否大于5?

    Expression body = Expression.Call(selector.Body, "IndexOf", null,
        Expression.Constant("cats", typeof(string)));
Run Code Online (Sandbox Code Playgroud)

c# lambda expression-trees

3
推荐指数
1
解决办法
59
查看次数

如何创建将表达式作为参数的通用表达式

DisplayNameFor(x=>x.Title)ASP.Net MVC 中有一个助手。我想实现类似的行为。

我想要一个方法,它接受基于User类(u=>u.Birthdate或 u=>u.Name)的表达式、一个操作数(更大、更少、等于)和一个类似的值DateTime.Now并返回一个表达式 u=>u.Birthdate > DateTime.Now

我知道我必须从片段手动构建结果表达式。我无法理解的是传入和处理属性表达式。

编辑:
我想调用一个方法,如
GetFilterPredicate(u=>u.Birthdate,FilterOps.GreaterThan,DateTime.Parse("01.01.2013")
GetFilterPredicate(u=>u.SomeIntProperty,FilterOps.Equals,2)

更新:我已经创建了一个 repo 来解决这个问题以及一个集合属性过滤 https://github.com/Alexander-Taran/Lambda-Magic-Filters

c# lambda func expression-trees

3
推荐指数
1
解决办法
4921
查看次数

使用表达式树而不是反射来获取和设置对象属性

我想动态获取和设置对象属性,如下所示:

public class Person
{
    public string Name {get; set; }
}

public class Testing
{
    public void Run()
    {
        var p = new Person();

        SetValue(p, "Name", "Henry");

        var name = GetValue(p, "Name");
    }
}
Run Code Online (Sandbox Code Playgroud)

请问我可以获得使用动态方法(或表达式树)创建 GetValue 和 SetValue 方法的帮助吗?

我打算将编译后的表达式保存在字典中,以加快将来的 get/set 调用速度。

c# reflection expression-trees dynamic-method

3
推荐指数
1
解决办法
2160
查看次数

为什么在Guid转换为字符串时,ExpandoObject无法正常工作?

如果传递两个字符串,我有一段代码可以正常工作.由于某种原因,如果将GUID转换为字符串,它将无法正常工作.

更详细的说,如果我创建一个新的ExpandoObject并传递字符串值,它可以工作,但如果我将GUID转换为字符串,则不会.

下面的代码应该比较两个参数.在我的例子中,我传递了相同的两个字符串.对于Equal运算符,true如果字符串相同则应该返回.如果第二个参数GUID转换为字符串,则返回false偶数字符串是相同的.dynamicObj.Add(memberName, Guid.Parse(value).ToString());

不知道我错过了什么.这是我的代码.

 string value = "642188c7-8e10-e111-961b-0ee1388ccc3b";

 string memberName = "State";
 string contactValue = value;

 var dynamicObj = (IDictionary<string, object>)new ExpandoObject();   dynamicObj.Add(memberName, Guid.Parse(value).ToString());

 var expression = Expression.Parameter(typeof(object), "arg");
 var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, null, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });

 var property = Expression.Dynamic(binder, typeof(object), expression);

 var isValid = false;
 var right = Expression.Constant(contactValue);
 var result = Expression.MakeBinary(ExpressionType.Equal, property, right);
 var func = typeof(Func<,>).MakeGenericType(dynamicObj.GetType(), typeof(bool));
 var expr = Expression.Lambda(func, result, expression).Compile();

 isValid = (bool)expr.DynamicInvoke(dynamicObj);
Run Code Online (Sandbox Code Playgroud)

c# linq lambda expression-trees

3
推荐指数
1
解决办法
161
查看次数

将 Expression&lt;Func&lt;T, U&gt;&gt; 转换为 Expression&lt;Func&lt;object, object&gt;&gt;

我有一个LambdaExpression类型为Expression<Func<T, string>>. 代码的设计目前不允许我保留T,这意味着我被迫使用较慢的DynamicInvoke而不是Invoke.

因为我知道T我想要转换表达式的类型,以便它接受一个T对象,允许我使用Invoke. 如何?

这是一个好的开始

class Program
{
    class MyClass
    {
        public string MyProperty => "Foo";
    }

    static LambdaExpression GetExpression(Expression<Func<MyClass, object>> expr)
    {
        return expr;
    }

    static void Main(string[] args)
    {
        var e1 = GetExpression(t => t.MyProperty);
        var e2 = Expression.Lambda<Func<object, object>>(e1, e1.Parameters);

        object myClass = new MyClass();
        string s1 = (string)e1.Compile().DynamicInvoke(myClass);
        object s2 = e2.Compile().Invoke(myClass);
    }
}
Run Code Online (Sandbox Code Playgroud)

c# lambda expression-trees

3
推荐指数
1
解决办法
1788
查看次数

如何在表达式树中编写 string.Contains(someText)

这是我学习表达式树的教程

我有超过 35 列要显示,但用户可以选择一次显示 10 列。因此,当用户在搜索框中键入内容时,我只想搜索用户可见的列。

SELECT FirstName, LastName, Address, ..., State
FROM Students
WHERE Id == @Id col1 AND (
      FirstName LIKE '%@searchText%' OR 
      LastName LIKE '%@searchText%' OR 
      Address LIKE '%@searchText%' OR 
      ...
      State LIKE '%@searchText%')
Run Code Online (Sandbox Code Playgroud)

回到 Linq,这就是我试图完成它的方式:

var result = db.Students
    .Where(GetPredicate(id, listOfColumns))
    .ToList();
Run Code Online (Sandbox Code Playgroud)

这是私有方法:

private Expression<Func<Student, bool>> GetPredicate(int id, List<string> listOfColumns)
{
   ParameterExpression pe = Expression.Parameter(typeof(Student), "s");

   Expression left0 = Expression.Property(pe, "Id");
   Expression right0 = Expression.Constant(id);
   Expression e0 = Expression.Equal(left0, right0);

   //Here ... omitted code …
Run Code Online (Sandbox Code Playgroud)

c# linq expression-trees

3
推荐指数
1
解决办法
1394
查看次数