Click here to Skip to main content
15,891,529 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I am doing some enhancement project.

I want to modify lambda expression tree so that I can compile it. In present logic :

Suppose I want data of some students from 8th std & 9th std. So the current expression tree is building like this:

std== 8th std and student= student 1
std== 8th std and student= student 2
std == 8th std and student = student 3.

std== 9th std and student= student 1
std== 9th std and student= student 2
std == 9th std and student = student 3.


As this is time consuming so I want to modify as:

std==8th and student in (student 1, student 2, student 3)
std==9th and student in (student 1, student 2, student 3) like this.

Any idea how to do this?
Posted
Updated 25-Sep-13 2:20am
v2
Comments
Maciej Los 25-Sep-13 9:08am    
Could you be more specific? Please, provide more details. At this time your question is not clear.
Surendra Patil 25-Sep-13 10:12am    
I want to build lambda expression tree. Currently the query code is building is very time consuming. Each time it's checking for Std and Student. Actually it should check only once for std and then the student from that std.

Like, currently it is always checking like below:

Std==8th && student==student1
st==8th && student==student 2

I want the logic like,
std==8th && student In(student1, student2).

Means instead of checking std all the time, just check it once then look for student from that std. Same for other std.

Something like,

Select Name, Age from Studend Where (Std=8 and StudentID In(student1, student2, student3))
OR (Std=9 and StudentID IN (student1, student2, student3))
Surendra Patil 25-Sep-13 10:26am    
Something like,

Select Name, Age from Studend Where (Std=8 and StudentID In(student1, student2, student3))
OR (Std=9 and StudentID IN (student1, student2, student3))

Your question is not conclusive: Do you ask for somethinng like dynamix LINQ[^]? Or an example of mine on CP: Invent your own Dynamic LINQ parser[^]?
They both take a string and convert it into an expression tree that is compiled and can be used for queries and alike (e.g. for LINQ queries).
Cheers
Andi
 
Share this answer
 
use this kind of expressions :

Student.Where(c => c.std == "8" && c=>c.student=="student1");
 
Share this answer
 
Comments
Surendra Patil 25-Sep-13 10:14am    
this won't help. Bcaz, this will only check for 1 student. I wan to check for 3 students with matching std.
Are your "student1", "student2", "student3" always these 3 values (or some 3 specific values)?
Or is the case that you have some collection of values?
C#
// if the ID values are always the same:
private static readonly List<string> IDs = new List<string>(){ "student1", "student2", "student3" };
public static bool MatchingStudent(StudentType student, int std)
{
  // add check for student being null!!
  // use the appropriate StringComparer based on your needs
  return student.std == std && IDs.Contains(student.StudentID, StringComparer.CurrentCultureIgnoreCase);
}
// if the ID values are in some collection:
public static bool MatchingStudent(StudentType student, int std, IEnumerable<string> studentIDs)
{
  // add checks for student and studentIDs being null!!
  // use the appropriate StringComparer based on your needs
  return student.std == std && studentIDs.Contains(student.StudentID, StringComparer.CurrentCultureIgnoreCase);
}

Then the usage is:
C#
var matching = Student.Where(s => MatchingStudent(s, 8));
// OR, depending on the cases above
var matching = Student.Where(s => MatchingStudent(s, 8, IDsCollection));


If you have the cases where the "std" value can be one of many, then you could extend the above with IEnumerable<int> stds instead of int std, and change the student.std == std to stds.Contains(student.std).
 
Share this answer
 
Comments
Surendra Patil 25-Sep-13 23:45pm    
HI Matt,

Actually they are building expression tree and later the point they are compiling it.

The tree forming is done with the help of aggregate function. In which each time it's checking for Std && Student combination multiple times (ex. (Std==8 && Student==1) || (Std==8 && Student==2)). But I want to check it only once for Std and once std matches, i want to check for student in it. like(ex. Std==8 && Student IN(1,2)). Here it's checking for std only once and then student in it.
Surendra Patil 26-Sep-13 0:00am    
Expression= Expression.or(Student.Aggregate(false, (curr, next)=> curr.or(line=>line.std==next.Std && line.student==next.Student));

Here next is list of students.

This is the code they have used.
Matt T Heffron 26-Sep-13 13:43pm    
Then I'd suggest first collecting all of the various conditions into some easily-manipulated data structures, do an analysis/simplification "pass" through it, and then build the expression tree after the simplification.
This is essentially a compiler to a semantic structure, optimization of the semantic structure, then code generation to the expression tree.
Surendra Patil 27-Sep-13 4:14am    
Thanks for your suggestion. Can you explain with some example.
Matt T Heffron 27-Sep-13 20:18pm    
See new Solution 3!
So, is the set of "queries" input from a file or user input?
I'm assuming here that they are all of the form:
Std==int && Student==string
At least semantically, if not literally.
So here's a fairly massive implementation of what you asked for!
I should have declared some new classes to hold the "semantic" information.
(Maybe I'll write an article. This drove me into learning more about Expressions. Thanks!)
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleApplication21
{
  class StudentType
  {
    public StudentType(int std, string id)
    {
      Std = std;
      StudentID = id;
    }
    public int Std { get; set; }
    public string StudentID { get; set; }
  }

  class Program
  {
    // The individual queries:
    static List<Tuple<int, string>> QueryInputs = new List<Tuple<int, string>> 
    { new Tuple<int, string>(8, "Student1"), 
      new Tuple<int, string>(8, "Student2"), 
      new Tuple<int, string>(8, "Student3"), 
      // If you uncomment the next line you'll see that only a single list of studentID strings is used where possible.
      //new Tuple<int, string>(9, "Student1"), 
      new Tuple<int, string>(9, "Student2"), 
      new Tuple<int, string>(9, "Student3") };

    // Test data to query against
    static List<StudentType> Student = new List<StudentType> {
      new StudentType(7, "Student1"),
      new StudentType(8, "Student0"),
      new StudentType(8, "Student1"),
      new StudentType(8, "Student3"),
      new StudentType(8, "Student2"),
      new StudentType(8, "Student10"),
      new StudentType(9, "Student0"),
      new StudentType(9, "Student2"),
      new StudentType(10, "Student3"),
    };

    // this is just to make getting the WhichStudentsInfo (MethodInfo) easier than dealing with a generic Where method
    private static IEnumerable<StudentType> WhichStudents(IEnumerable<StudentType> students, Func<StudentType, bool> test)
    {
      return students.Where(test);
    }

    private static Dictionary<int, List<string>> QuerySemantics = new Dictionary<int, List<string>>();
    private static MethodInfo ContainsInfo = typeof(List<string>).GetMethod("Contains");
    private static MethodInfo WhichStudentsInfo = typeof(Program).GetMethod("WhichStudents", BindingFlags.NonPublic | BindingFlags.Static);
    private static ParameterExpression ArgumentParameter = Expression.Parameter(typeof(StudentType), "s");
    private static ParameterExpression OuterArgumentParameter = Expression.Parameter(typeof(IEnumerable<StudentType>), "students");
    static void Main(string[] args)
    {
      foreach (var item in QueryInputs)
      {
        int queryStd = item.Item1;
        string queryStudent = item.Item2;
        // Then add to the QuerySemantics:
        List<string> studentList;
        if (!QuerySemantics.TryGetValue(queryStd, out studentList))
        {
          studentList = new List<string>();
          QuerySemantics.Add(queryStd, studentList);
        }
        studentList.Add(queryStudent);
      }
      Expression fullQueryExpression = null;
      // first go through and generate the unique multiple student lists
      Dictionary<string, string> studentListMap = new Dictionary<string, string>();
      Dictionary<string, BinaryExpression> studentListVariableExpressions = new Dictionary<string, BinaryExpression>();
      int listCounter = 0;
      foreach (var q in QuerySemantics)
      {
        var qStudents = q.Value;
        if (qStudents.Count > 1)
        {
          qStudents.Sort();
          string key = string.Concat(qStudents);  // good enough for uniqueness
          string listVar;
          if (!studentListMap.TryGetValue(key, out listVar))
          {
            listVar = "sl" + (listCounter++).ToString();
            studentListMap.Add(key, listVar);
            var varExpression = Expression.Assign(Expression.Variable(typeof(List<string>), listVar),
                                                  Expression.ListInit(Expression.New(typeof(List<string>)),
                                                                                     qStudents.Select(s => Expression.Constant(s))));
            studentListVariableExpressions.Add(listVar, varExpression);
          }
          qStudents.Insert(0, listVar);
        }
      }
      foreach (var q in QuerySemantics)
      {
        Expression queryExpression = null;
        var qStdExpression = Expression.Equal(Expression.Constant(q.Key),
                                              Expression.Property(ArgumentParameter, "Std"));
        var qStudents = q.Value;
        Expression qStudentsExpression = null;
        if (qStudents.Count > 1)
        {
          var studentListVar = studentListVariableExpressions[qStudents[0]];  // if multiple entries then 1st is var name 
          qStudentsExpression = Expression.Call(studentListVar.Left, ContainsInfo,
                                                Expression.Property(ArgumentParameter, "StudentID"));
        }
        else
        {
          qStudentsExpression = Expression.Equal(Expression.Constant(qStudents[0]),
                                                 Expression.Property(ArgumentParameter, "StudentID"));
        }
        queryExpression = Expression.AndAlso(qStdExpression, qStudentsExpression);
        if (fullQueryExpression == null)
        {
          fullQueryExpression = queryExpression;
        }
        else
        {
          fullQueryExpression = Expression.OrElse(fullQueryExpression, queryExpression);
        }
      }
      var lambdaQueryExpression = Expression.Lambda<Func<StudentType, bool>>(fullQueryExpression, ArgumentParameter);
      var variables = studentListVariableExpressions.Values.Select(lve => lve.Left).Cast<ParameterExpression>();
      var expressionsList = studentListVariableExpressions.Values.Cast<Expression>().ToList();
      expressionsList.Add(Expression.Call(WhichStudentsInfo, OuterArgumentParameter, lambdaQueryExpression));
      var whichStudentsBlock = Expression.Block(typeof(IEnumerable<StudentType>), variables, expressionsList);
      var lambdaWhichStudentsExpression = Expression.Lambda<Func<IEnumerable<StudentType>,
                                                                 IEnumerable<StudentType>>>(whichStudentsBlock,
                                                                                            OuterArgumentParameter);
      // In the Debugger ONLY you can breakpoint here and look at lambdaWhichStudentsExpression.DebugView to see what this all is!!
      var compiled = lambdaWhichStudentsExpression.Compile();
      foreach (var s in compiled(Student))
      {
        Console.WriteLine("Std: {0}, StudentID: {1}", s.Std, s.StudentID);
      }
    }
  }
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900