LINQ Tips #7 Create a LINQ to Anything(3)

Yesterday, we implemented a simple LINQ to Objects pattern. In our post, we overwrote the  data source , if you can remember, all the return value were added a tail as "LINQ".

But this seems useless, in the NFlickr project, we need to send the filter to the Flickr service and get the filtered result.So we need to implement the "Where"  clause.

Before we start, can you answer the question first?

If we want to implement the new clause like "Where","Orderby", where we should implement?

The answer is the method (CreateQuery) for the interface IQueryProvider!

Yesterday, we only handled the "Select" clause, I will add a new case switch to implement the "Where" condition.

   1:              case "Where":
   2:                              StringBuilder sb = new StringBuilder();
   3:   
   4:                              functions = new List<KeyValuePair<string, Func<int>>>();
   5:                              filterList = new List<string>();
   6:                              LambdaExpression lambdaExpression = (LambdaExpression)(((UnaryExpression)callExpression.Arguments[1]).Operand);
   7:                              ExpandExpression(lambdaExpression.Body);
   8:                              return (IQueryable<TElement>)this;

The key point is to cast the callExpression from the Expression to LambdaExpression. After we got the LambdaExpression, we can go inside the method ExpendExpression.

   1:          List<string> filterList = null;
   2:          public void ExpandExpression(Expression lambdaExpression)
   3:          {
   4:              switch (lambdaExpression.NodeType)
   5:              {
   6:                  case ExpressionType.Equal:
   7:                      Expression right = (BinaryExpression)lambdaExpression;
   8:                      filterList.Add((string)((ConstantExpression)right).Value);
   9:                      break;
  10:              }
  11:          }

This function is to preserver the filter list and this list will be used we the code is to return the data source.

        public IEnumerator<Student> GetEnumerator()
        {
            
            IEnumerator<Student> list = (IEnumerator<Student>)this;
            if (functions == null)
                return list;

            List<Student> result = new List<Student>();

            foreach (Student student in students)
            {
                foreach (string filter in filterList)
                {
                    if (student.FirstName.Equals(filter, StringComparison.OrdinalIgnoreCase))
                    {
                        result.Add(student);
                    }
                }
            }
            return result.GetEnumerator();
            
        }

Now, we changed the behavior from the original  LINQ expression from the case sensitive to not-sensitive.

   1:    var classmates = from classmate in GetClassRoom2()
   2:                               where classmate.FirstName=="tom"
   3:                               select classmate;

And

 

   1:    var classmates = from classmate in GetClassRoom2()
   2:                               where classmate.FirstName=="Tom"
   3:                               select classmate;

will be the same result.

From now, a simple version of the LINQ to "Anything" can be released, welcome to send me email or leave a comment about this topic.

Published Tuesday, November 11, 2008 10:42 PM by RobertNet
Filed under: ,

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)