Linq 动态查询排序

Linq的排序一般是这样写的:

query.OrderBy(x => x.Tel).Skip(0).Take(10);

实际使用中排序字段可能是通过字符类型的参数来设置的,于是想这样实现:

query.OrderBy(x=>x.GetType().GetField("Tel")).Skip(0).Take(10);

上面的写法是无法编译通过的,此路不通,于是找到一个order扩展类:

 1 using System;
 2 using System.Linq;
 3 using System.Linq.Expressions;
 4 using System.Collections.Generic;
 5 using System.Reflection;
 6
 7 public static class OrderExtension
 8 {
 9     public static IOrderedQueryable<T> DynamicOrderBy<T>(this IQueryable<T> source, string property)
10     {
11         return ApplyOrder<T>(source, property, "OrderBy");
12     }
13
14     public static IOrderedQueryable<T> DynamicOrderByDescending<T>(this IQueryable<T> source, string property)
15     {
16         return ApplyOrder<T>(source, property, "OrderByDescending");
17     }
18
19     public static IOrderedQueryable<T> DynamicThenBy<T>(this IOrderedQueryable<T> source, string property)
20     {
21         return ApplyOrder<T>(source, property, "ThenBy");
22     }
23
24     public static IOrderedQueryable<T> DynamicThenByDescending<T>(this IOrderedQueryable<T> source, string property)
25     {
26         return ApplyOrder<T>(source, property, "ThenByDescending");
27     }
28
29     static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
30     {
31         string[] props = property.Split(‘.‘);
32         Type type = typeof(T); ParameterExpression arg = Expression.Parameter(type, "x");
33         Expression expr = arg; foreach (string prop in props)
34         {
35             // use reflection (not ComponentModel) to mirror LINQ
36             PropertyInfo pi = type.GetProperty(prop); expr = Expression.Property(expr, pi); type = pi.PropertyType;
37         }
38         Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
39         LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
40         object result = typeof(Queryable).GetMethods().Single(method => method.Name == methodName
41                         && method.IsGenericMethodDefinition
42                         && method.GetGenericArguments().Length == 2
43                         && method.GetParameters().Length == 2)
44                         .MakeGenericMethod(typeof(T), type)
45                         .Invoke(null, new object[] { source, lambda });
46         return (IOrderedQueryable<T>)result;
47     }
48 }

OrderExtension

排序可以这样处理了:

query.DynamicOrderBy("Tel").Skip(0).Take(10);

排序问题解决了,查询还是没解决,MongoDb Linq的查询语句一般是这样的:

var query = collection.AsQueryable<Customer>().Where(e => e.CustomerName == searchWord);

如果将where条件分开写是这样的:

System.Linq.Expressions.Expression<Func<Customer, bool>> expression = e => e.CustomerName == searchWord;
var query = collection.AsQueryable<Customer>().Where(expression);

那么问题来了,我想动态添加个where条件是否可以这样写呢:

System.Linq.Expressions.Expression<Func<Customer, bool>> expression = e => e.CustomerName == searchWord;
expression += e => e.Tel == "123456789";
var query = collection.AsQueryable<Customer>().Where(expression);

这样想当然的代码当然不能编译通过了~

继续google,找到一个PredicateBuilder类:

 1 using System;
 2 using System.Linq;
 3 using System.Linq.Expressions;
 4 using System.Collections.Generic;
 5
 6 using System.Reflection;
 7 using MongoDB.Driver.Linq;
 8
 9 public static class PredicateBuilder
10 {
11     public static Expression<Func<T, bool>> True<T>() { return f => true; }
12     public static Expression<Func<T, bool>> False<T>() { return f => false; }
13     public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
14     {
15         // build parameter map (from parameters of second to parameters of first)
16         var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
17
18         // replace parameters in the second lambda expression with parameters from the first
19         var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
20
21         // apply composition of lambda expression bodies to parameters from the first expression
22         return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
23     }
24
25     public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
26     {
27         return first.Compose(second, Expression.And);
28     }
29     public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
30     {
31         return first.Compose(second, Expression.Or);
32     }
33
34     public static object GetPropertyValue(object obj, string property)
35     {
36         System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
37         return propertyInfo.GetValue(obj, null);
38     }
39 }
40
41 public class ParameterRebinder : ExpressionVisitor
42 {
43     private readonly Dictionary<ParameterExpression, ParameterExpression> map;
44
45     public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
46     {
47         this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
48     }
49
50     public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
51     {
52         return new ParameterRebinder(map).Visit(exp);
53     }
54
55     protected override Expression VisitParameter(ParameterExpression p)
56     {
57         ParameterExpression replacement;
58         if (map.TryGetValue(p, out replacement))
59         {
60             p = replacement;
61         }
62         return base.VisitParameter(p);
63     }
64 }

class PredicateBuilder

于是查询可以这样写了:

//Linq 强类型动态查询
System.Linq.Expressions.Expression<Func<Customer, bool>> expression = PredicateBuilder.True<Customer>();
if (!string.IsNullOrEmpty(searchWord))
{
    expression = expression.And(e => e.CustomerName == searchWord);
    expression = expression.And(e => e.Tel != "");
    expression = expression.And(e => e.ContactName.Contains("ContactName"));
}
var query = collection.AsQueryable<Customer>().Where(expression);

还有Dynamic LINQ可以参考: http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library

   1 using System;
   2 using System.Collections.Generic;
   3 using System.Text;
   4 using System.Linq;
   5 using System.Linq.Expressions;
   6 using System.Reflection;
   7 using System.Reflection.Emit;
   8 using System.Threading;
   9
  10 namespace System.Linq.Dynamic
  11 {
  12     public static class DynamicQueryable
  13     {
  14         public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
  15         {
  16             return (IQueryable<T>)Where((IQueryable)source, predicate, values);
  17         }
  18
  19         public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
  20         {
  21             if (source == null) throw new ArgumentNullException("source");
  22             if (predicate == null) throw new ArgumentNullException("predicate");
  23             LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
  24             return source.Provider.CreateQuery(
  25                 Expression.Call(
  26                     typeof(Queryable), "Where",
  27                     new Type[] { source.ElementType },
  28                     source.Expression, Expression.Quote(lambda)));
  29         }
  30
  31         public static IQueryable Select(this IQueryable source, string selector, params object[] values)
  32         {
  33             if (source == null) throw new ArgumentNullException("source");
  34             if (selector == null) throw new ArgumentNullException("selector");
  35             LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
  36             return source.Provider.CreateQuery(
  37                 Expression.Call(
  38                     typeof(Queryable), "Select",
  39                     new Type[] { source.ElementType, lambda.Body.Type },
  40                     source.Expression, Expression.Quote(lambda)));
  41         }
  42
  43         public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
  44         {
  45             return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
  46         }
  47
  48         public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
  49         {
  50             if (source == null) throw new ArgumentNullException("source");
  51             if (ordering == null) throw new ArgumentNullException("ordering");
  52             ParameterExpression[] parameters = new ParameterExpression[] {
  53                 Expression.Parameter(source.ElementType, "") };
  54             ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
  55             IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
  56             Expression queryExpr = source.Expression;
  57             string methodAsc = "OrderBy";
  58             string methodDesc = "OrderByDescending";
  59             foreach (DynamicOrdering o in orderings)
  60             {
  61                 queryExpr = Expression.Call(
  62                     typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
  63                     new Type[] { source.ElementType, o.Selector.Type },
  64                     queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
  65                 methodAsc = "ThenBy";
  66                 methodDesc = "ThenByDescending";
  67             }
  68             return source.Provider.CreateQuery(queryExpr);
  69         }
  70
  71         public static IQueryable Take(this IQueryable source, int count)
  72         {
  73             if (source == null) throw new ArgumentNullException("source");
  74             return source.Provider.CreateQuery(
  75                 Expression.Call(
  76                     typeof(Queryable), "Take",
  77                     new Type[] { source.ElementType },
  78                     source.Expression, Expression.Constant(count)));
  79         }
  80
  81         public static IQueryable Skip(this IQueryable source, int count)
  82         {
  83             if (source == null) throw new ArgumentNullException("source");
  84             return source.Provider.CreateQuery(
  85                 Expression.Call(
  86                     typeof(Queryable), "Skip",
  87                     new Type[] { source.ElementType },
  88                     source.Expression, Expression.Constant(count)));
  89         }
  90
  91         public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
  92         {
  93             if (source == null) throw new ArgumentNullException("source");
  94             if (keySelector == null) throw new ArgumentNullException("keySelector");
  95             if (elementSelector == null) throw new ArgumentNullException("elementSelector");
  96             LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);
  97             LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);
  98             return source.Provider.CreateQuery(
  99                 Expression.Call(
 100                     typeof(Queryable), "GroupBy",
 101                     new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
 102                     source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));
 103         }
 104
 105         public static bool Any(this IQueryable source)
 106         {
 107             if (source == null) throw new ArgumentNullException("source");
 108             return (bool)source.Provider.Execute(
 109                 Expression.Call(
 110                     typeof(Queryable), "Any",
 111                     new Type[] { source.ElementType }, source.Expression));
 112         }
 113
 114         public static int Count(this IQueryable source)
 115         {
 116             if (source == null) throw new ArgumentNullException("source");
 117             return (int)source.Provider.Execute(
 118                 Expression.Call(
 119                     typeof(Queryable), "Count",
 120                     new Type[] { source.ElementType }, source.Expression));
 121         }
 122     }
 123
 124     public abstract class DynamicClass
 125     {
 126         public override string ToString()
 127         {
 128             PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
 129             StringBuilder sb = new StringBuilder();
 130             sb.Append("{");
 131             for (int i = 0; i < props.Length; i++)
 132             {
 133                 if (i > 0) sb.Append(", ");
 134                 sb.Append(props[i].Name);
 135                 sb.Append("=");
 136                 sb.Append(props[i].GetValue(this, null));
 137             }
 138             sb.Append("}");
 139             return sb.ToString();
 140         }
 141     }
 142
 143     public class DynamicProperty
 144     {
 145         string name;
 146         Type type;
 147
 148         public DynamicProperty(string name, Type type)
 149         {
 150             if (name == null) throw new ArgumentNullException("name");
 151             if (type == null) throw new ArgumentNullException("type");
 152             this.name = name;
 153             this.type = type;
 154         }
 155
 156         public string Name
 157         {
 158             get { return name; }
 159         }
 160
 161         public Type Type
 162         {
 163             get { return type; }
 164         }
 165     }
 166
 167     public static class DynamicExpression
 168     {
 169         public static Expression Parse(Type resultType, string expression, params object[] values)
 170         {
 171             ExpressionParser parser = new ExpressionParser(null, expression, values);
 172             return parser.Parse(resultType);
 173         }
 174
 175         public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)
 176         {
 177             return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, values);
 178         }
 179
 180         public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
 181         {
 182             ExpressionParser parser = new ExpressionParser(parameters, expression, values);
 183             return Expression.Lambda(parser.Parse(resultType), parameters);
 184         }
 185
 186         public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values)
 187         {
 188             return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);
 189         }
 190
 191         public static Type CreateClass(params DynamicProperty[] properties)
 192         {
 193             return ClassFactory.Instance.GetDynamicClass(properties);
 194         }
 195
 196         public static Type CreateClass(IEnumerable<DynamicProperty> properties)
 197         {
 198             return ClassFactory.Instance.GetDynamicClass(properties);
 199         }
 200     }
 201
 202     internal class DynamicOrdering
 203     {
 204         public Expression Selector;
 205         public bool Ascending;
 206     }
 207
 208     internal class Signature : IEquatable<Signature>
 209     {
 210         public DynamicProperty[] properties;
 211         public int hashCode;
 212
 213         public Signature(IEnumerable<DynamicProperty> properties)
 214         {
 215             this.properties = properties.ToArray();
 216             hashCode = 0;
 217             foreach (DynamicProperty p in properties)
 218             {
 219                 hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
 220             }
 221         }
 222
 223         public override int GetHashCode()
 224         {
 225             return hashCode;
 226         }
 227
 228         public override bool Equals(object obj)
 229         {
 230             return obj is Signature ? Equals((Signature)obj) : false;
 231         }
 232
 233         public bool Equals(Signature other)
 234         {
 235             if (properties.Length != other.properties.Length) return false;
 236             for (int i = 0; i < properties.Length; i++)
 237             {
 238                 if (properties[i].Name != other.properties[i].Name ||
 239                     properties[i].Type != other.properties[i].Type) return false;
 240             }
 241             return true;
 242         }
 243     }
 244
 245     internal class ClassFactory
 246     {
 247         public static readonly ClassFactory Instance = new ClassFactory();
 248
 249         static ClassFactory() { }  // Trigger lazy initialization of static fields
 250
 251         ModuleBuilder module;
 252         Dictionary<Signature, Type> classes;
 253         int classCount;
 254         ReaderWriterLock rwLock;
 255
 256         private ClassFactory()
 257         {
 258             AssemblyName name = new AssemblyName("DynamicClasses");
 259             AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
 260 #if ENABLE_LINQ_PARTIAL_TRUST
 261             new ReflectionPermission(PermissionState.Unrestricted).Assert();
 262 #endif
 263             try
 264             {
 265                 module = assembly.DefineDynamicModule("Module");
 266             }
 267             finally
 268             {
 269 #if ENABLE_LINQ_PARTIAL_TRUST
 270                 PermissionSet.RevertAssert();
 271 #endif
 272             }
 273             classes = new Dictionary<Signature, Type>();
 274             rwLock = new ReaderWriterLock();
 275         }
 276
 277         public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
 278         {
 279             rwLock.AcquireReaderLock(Timeout.Infinite);
 280             try
 281             {
 282                 Signature signature = new Signature(properties);
 283                 Type type;
 284                 if (!classes.TryGetValue(signature, out type))
 285                 {
 286                     type = CreateDynamicClass(signature.properties);
 287                     classes.Add(signature, type);
 288                 }
 289                 return type;
 290             }
 291             finally
 292             {
 293                 rwLock.ReleaseReaderLock();
 294             }
 295         }
 296
 297         Type CreateDynamicClass(DynamicProperty[] properties)
 298         {
 299             LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
 300             try
 301             {
 302                 string typeName = "DynamicClass" + (classCount + 1);
 303 #if ENABLE_LINQ_PARTIAL_TRUST
 304                 new ReflectionPermission(PermissionState.Unrestricted).Assert();
 305 #endif
 306                 try
 307                 {
 308                     TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
 309                         TypeAttributes.Public, typeof(DynamicClass));
 310                     FieldInfo[] fields = GenerateProperties(tb, properties);
 311                     GenerateEquals(tb, fields);
 312                     GenerateGetHashCode(tb, fields);
 313                     Type result = tb.CreateType();
 314                     classCount++;
 315                     return result;
 316                 }
 317                 finally
 318                 {
 319 #if ENABLE_LINQ_PARTIAL_TRUST
 320                     PermissionSet.RevertAssert();
 321 #endif
 322                 }
 323             }
 324             finally
 325             {
 326                 rwLock.DowngradeFromWriterLock(ref cookie);
 327             }
 328         }
 329
 330         FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
 331         {
 332             FieldInfo[] fields = new FieldBuilder[properties.Length];
 333             for (int i = 0; i < properties.Length; i++)
 334             {
 335                 DynamicProperty dp = properties[i];
 336                 FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private);
 337                 PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);
 338                 MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name,
 339                     MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
 340                     dp.Type, Type.EmptyTypes);
 341                 ILGenerator genGet = mbGet.GetILGenerator();
 342                 genGet.Emit(OpCodes.Ldarg_0);
 343                 genGet.Emit(OpCodes.Ldfld, fb);
 344                 genGet.Emit(OpCodes.Ret);
 345                 MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name,
 346                     MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
 347                     null, new Type[] { dp.Type });
 348                 ILGenerator genSet = mbSet.GetILGenerator();
 349                 genSet.Emit(OpCodes.Ldarg_0);
 350                 genSet.Emit(OpCodes.Ldarg_1);
 351                 genSet.Emit(OpCodes.Stfld, fb);
 352                 genSet.Emit(OpCodes.Ret);
 353                 pb.SetGetMethod(mbGet);
 354                 pb.SetSetMethod(mbSet);
 355                 fields[i] = fb;
 356             }
 357             return fields;
 358         }
 359
 360         void GenerateEquals(TypeBuilder tb, FieldInfo[] fields)
 361         {
 362             MethodBuilder mb = tb.DefineMethod("Equals",
 363                 MethodAttributes.Public | MethodAttributes.ReuseSlot |
 364                 MethodAttributes.Virtual | MethodAttributes.HideBySig,
 365                 typeof(bool), new Type[] { typeof(object) });
 366             ILGenerator gen = mb.GetILGenerator();
 367             LocalBuilder other = gen.DeclareLocal(tb);
 368             Label next = gen.DefineLabel();
 369             gen.Emit(OpCodes.Ldarg_1);
 370             gen.Emit(OpCodes.Isinst, tb);
 371             gen.Emit(OpCodes.Stloc, other);
 372             gen.Emit(OpCodes.Ldloc, other);
 373             gen.Emit(OpCodes.Brtrue_S, next);
 374             gen.Emit(OpCodes.Ldc_I4_0);
 375             gen.Emit(OpCodes.Ret);
 376             gen.MarkLabel(next);
 377             foreach (FieldInfo field in fields)
 378             {
 379                 Type ft = field.FieldType;
 380                 Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
 381                 next = gen.DefineLabel();
 382                 gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
 383                 gen.Emit(OpCodes.Ldarg_0);
 384                 gen.Emit(OpCodes.Ldfld, field);
 385                 gen.Emit(OpCodes.Ldloc, other);
 386                 gen.Emit(OpCodes.Ldfld, field);
 387                 gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null);
 388                 gen.Emit(OpCodes.Brtrue_S, next);
 389                 gen.Emit(OpCodes.Ldc_I4_0);
 390                 gen.Emit(OpCodes.Ret);
 391                 gen.MarkLabel(next);
 392             }
 393             gen.Emit(OpCodes.Ldc_I4_1);
 394             gen.Emit(OpCodes.Ret);
 395         }
 396
 397         void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)
 398         {
 399             MethodBuilder mb = tb.DefineMethod("GetHashCode",
 400                 MethodAttributes.Public | MethodAttributes.ReuseSlot |
 401                 MethodAttributes.Virtual | MethodAttributes.HideBySig,
 402                 typeof(int), Type.EmptyTypes);
 403             ILGenerator gen = mb.GetILGenerator();
 404             gen.Emit(OpCodes.Ldc_I4_0);
 405             foreach (FieldInfo field in fields)
 406             {
 407                 Type ft = field.FieldType;
 408                 Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
 409                 gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
 410                 gen.Emit(OpCodes.Ldarg_0);
 411                 gen.Emit(OpCodes.Ldfld, field);
 412                 gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);
 413                 gen.Emit(OpCodes.Xor);
 414             }
 415             gen.Emit(OpCodes.Ret);
 416         }
 417     }
 418
 419     public sealed class ParseException : Exception
 420     {
 421         int position;
 422
 423         public ParseException(string message, int position)
 424             : base(message)
 425         {
 426             this.position = position;
 427         }
 428
 429         public int Position
 430         {
 431             get { return position; }
 432         }
 433
 434         public override string ToString()
 435         {
 436             return string.Format(Res.ParseExceptionFormat, Message, position);
 437         }
 438     }
 439
 440     internal class ExpressionParser
 441     {
 442         struct Token
 443         {
 444             public TokenId id;
 445             public string text;
 446             public int pos;
 447         }
 448
 449         enum TokenId
 450         {
 451             Unknown,
 452             End,
 453             Identifier,
 454             StringLiteral,
 455             IntegerLiteral,
 456             RealLiteral,
 457             Exclamation,
 458             Percent,
 459             Amphersand,
 460             OpenParen,
 461             CloseParen,
 462             Asterisk,
 463             Plus,
 464             Comma,
 465             Minus,
 466             Dot,
 467             Slash,
 468             Colon,
 469             LessThan,
 470             Equal,
 471             GreaterThan,
 472             Question,
 473             OpenBracket,
 474             CloseBracket,
 475             Bar,
 476             ExclamationEqual,
 477             DoubleAmphersand,
 478             LessThanEqual,
 479             LessGreater,
 480             DoubleEqual,
 481             GreaterThanEqual,
 482             DoubleBar
 483         }
 484
 485         interface ILogicalSignatures
 486         {
 487             void F(bool x, bool y);
 488             void F(bool? x, bool? y);
 489         }
 490
 491         interface IArithmeticSignatures
 492         {
 493             void F(int x, int y);
 494             void F(uint x, uint y);
 495             void F(long x, long y);
 496             void F(ulong x, ulong y);
 497             void F(float x, float y);
 498             void F(double x, double y);
 499             void F(decimal x, decimal y);
 500             void F(int? x, int? y);
 501             void F(uint? x, uint? y);
 502             void F(long? x, long? y);
 503             void F(ulong? x, ulong? y);
 504             void F(float? x, float? y);
 505             void F(double? x, double? y);
 506             void F(decimal? x, decimal? y);
 507         }
 508
 509         interface IRelationalSignatures : IArithmeticSignatures
 510         {
 511             void F(string x, string y);
 512             void F(char x, char y);
 513             void F(DateTime x, DateTime y);
 514             void F(TimeSpan x, TimeSpan y);
 515             void F(char? x, char? y);
 516             void F(DateTime? x, DateTime? y);
 517             void F(TimeSpan? x, TimeSpan? y);
 518         }
 519
 520         interface IEqualitySignatures : IRelationalSignatures
 521         {
 522             void F(bool x, bool y);
 523             void F(bool? x, bool? y);
 524         }
 525
 526         interface IAddSignatures : IArithmeticSignatures
 527         {
 528             void F(DateTime x, TimeSpan y);
 529             void F(TimeSpan x, TimeSpan y);
 530             void F(DateTime? x, TimeSpan? y);
 531             void F(TimeSpan? x, TimeSpan? y);
 532         }
 533
 534         interface ISubtractSignatures : IAddSignatures
 535         {
 536             void F(DateTime x, DateTime y);
 537             void F(DateTime? x, DateTime? y);
 538         }
 539
 540         interface INegationSignatures
 541         {
 542             void F(int x);
 543             void F(long x);
 544             void F(float x);
 545             void F(double x);
 546             void F(decimal x);
 547             void F(int? x);
 548             void F(long? x);
 549             void F(float? x);
 550             void F(double? x);
 551             void F(decimal? x);
 552         }
 553
 554         interface INotSignatures
 555         {
 556             void F(bool x);
 557             void F(bool? x);
 558         }
 559
 560         interface IEnumerableSignatures
 561         {
 562             void Where(bool predicate);
 563             void Any();
 564             void Any(bool predicate);
 565             void All(bool predicate);
 566             void Count();
 567             void Count(bool predicate);
 568             void Min(object selector);
 569             void Max(object selector);
 570             void Sum(int selector);
 571             void Sum(int? selector);
 572             void Sum(long selector);
 573             void Sum(long? selector);
 574             void Sum(float selector);
 575             void Sum(float? selector);
 576             void Sum(double selector);
 577             void Sum(double? selector);
 578             void Sum(decimal selector);
 579             void Sum(decimal? selector);
 580             void Average(int selector);
 581             void Average(int? selector);
 582             void Average(long selector);
 583             void Average(long? selector);
 584             void Average(float selector);
 585             void Average(float? selector);
 586             void Average(double selector);
 587             void Average(double? selector);
 588             void Average(decimal selector);
 589             void Average(decimal? selector);
 590         }
 591
 592         static readonly Type[] predefinedTypes = {
 593             typeof(Object),
 594             typeof(Boolean),
 595             typeof(Char),
 596             typeof(String),
 597             typeof(SByte),
 598             typeof(Byte),
 599             typeof(Int16),
 600             typeof(UInt16),
 601             typeof(Int32),
 602             typeof(UInt32),
 603             typeof(Int64),
 604             typeof(UInt64),
 605             typeof(Single),
 606             typeof(Double),
 607             typeof(Decimal),
 608             typeof(DateTime),
 609             typeof(TimeSpan),
 610             typeof(Guid),
 611             typeof(Math),
 612             typeof(Convert)
 613         };
 614
 615         static readonly Expression trueLiteral = Expression.Constant(true);
 616         static readonly Expression falseLiteral = Expression.Constant(false);
 617         static readonly Expression nullLiteral = Expression.Constant(null);
 618
 619         static readonly string keywordIt = "it";
 620         static readonly string keywordIif = "iif";
 621         static readonly string keywordNew = "new";
 622
 623         static Dictionary<string, object> keywords;
 624
 625         Dictionary<string, object> symbols;
 626         IDictionary<string, object> externals;
 627         Dictionary<Expression, string> literals;
 628         ParameterExpression it;
 629         string text;
 630         int textPos;
 631         int textLen;
 632         char ch;
 633         Token token;
 634
 635         public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
 636         {
 637             if (expression == null) throw new ArgumentNullException("expression");
 638             if (keywords == null) keywords = CreateKeywords();
 639             symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
 640             literals = new Dictionary<Expression, string>();
 641             if (parameters != null) ProcessParameters(parameters);
 642             if (values != null) ProcessValues(values);
 643             text = expression;
 644             textLen = text.Length;
 645             SetTextPos(0);
 646             NextToken();
 647         }
 648
 649         void ProcessParameters(ParameterExpression[] parameters)
 650         {
 651             foreach (ParameterExpression pe in parameters)
 652                 if (!String.IsNullOrEmpty(pe.Name))
 653                     AddSymbol(pe.Name, pe);
 654             if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
 655                 it = parameters[0];
 656         }
 657
 658         void ProcessValues(object[] values)
 659         {
 660             for (int i = 0; i < values.Length; i++)
 661             {
 662                 object value = values[i];
 663                 if (i == values.Length - 1 && value is IDictionary<string, object>)
 664                 {
 665                     externals = (IDictionary<string, object>)value;
 666                 }
 667                 else
 668                 {
 669                     AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);
 670                 }
 671             }
 672         }
 673
 674         void AddSymbol(string name, object value)
 675         {
 676             if (symbols.ContainsKey(name))
 677                 throw ParseError(Res.DuplicateIdentifier, name);
 678             symbols.Add(name, value);
 679         }
 680
 681         public Expression Parse(Type resultType)
 682         {
 683             int exprPos = token.pos;
 684             Expression expr = ParseExpression();
 685             if (resultType != null)
 686                 if ((expr = PromoteExpression(expr, resultType, true)) == null)
 687                     throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));
 688             ValidateToken(TokenId.End, Res.SyntaxError);
 689             return expr;
 690         }
 691
 692 #pragma warning disable 0219
 693         public IEnumerable<DynamicOrdering> ParseOrdering()
 694         {
 695             List<DynamicOrdering> orderings = new List<DynamicOrdering>();
 696             while (true)
 697             {
 698                 Expression expr = ParseExpression();
 699                 bool ascending = true;
 700                 if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
 701                 {
 702                     NextToken();
 703                 }
 704                 else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
 705                 {
 706                     NextToken();
 707                     ascending = false;
 708                 }
 709                 orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });
 710                 if (token.id != TokenId.Comma) break;
 711                 NextToken();
 712             }
 713             ValidateToken(TokenId.End, Res.SyntaxError);
 714             return orderings;
 715         }
 716 #pragma warning restore 0219
 717
 718         // ?: operator
 719         Expression ParseExpression()
 720         {
 721             int errorPos = token.pos;
 722             Expression expr = ParseLogicalOr();
 723             if (token.id == TokenId.Question)
 724             {
 725                 NextToken();
 726                 Expression expr1 = ParseExpression();
 727                 ValidateToken(TokenId.Colon, Res.ColonExpected);
 728                 NextToken();
 729                 Expression expr2 = ParseExpression();
 730                 expr = GenerateConditional(expr, expr1, expr2, errorPos);
 731             }
 732             return expr;
 733         }
 734
 735         // ||, or operator
 736         Expression ParseLogicalOr()
 737         {
 738             Expression left = ParseLogicalAnd();
 739             while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
 740             {
 741                 Token op = token;
 742                 NextToken();
 743                 Expression right = ParseLogicalAnd();
 744                 CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
 745                 left = Expression.OrElse(left, right);
 746             }
 747             return left;
 748         }
 749
 750         // &&, and operator
 751         Expression ParseLogicalAnd()
 752         {
 753             Expression left = ParseComparison();
 754             while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
 755             {
 756                 Token op = token;
 757                 NextToken();
 758                 Expression right = ParseComparison();
 759                 CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
 760                 left = Expression.AndAlso(left, right);
 761             }
 762             return left;
 763         }
 764
 765         // =, ==, !=, <>, >, >=, <, <= operators
 766         Expression ParseComparison()
 767         {
 768             Expression left = ParseAdditive();
 769             while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual ||
 770                 token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater ||
 771                 token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual ||
 772                 token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual)
 773             {
 774                 Token op = token;
 775                 NextToken();
 776                 Expression right = ParseAdditive();
 777                 bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual ||
 778                     op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater;
 779                 if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType)
 780                 {
 781                     if (left.Type != right.Type)
 782                     {
 783                         if (left.Type.IsAssignableFrom(right.Type))
 784                         {
 785                             right = Expression.Convert(right, left.Type);
 786                         }
 787                         else if (right.Type.IsAssignableFrom(left.Type))
 788                         {
 789                             left = Expression.Convert(left, right.Type);
 790                         }
 791                         else
 792                         {
 793                             throw IncompatibleOperandsError(op.text, left, right, op.pos);
 794                         }
 795                     }
 796                 }
 797                 else if (IsEnumType(left.Type) || IsEnumType(right.Type))
 798                 {
 799                     if (left.Type != right.Type)
 800                     {
 801                         Expression e;
 802                         if ((e = PromoteExpression(right, left.Type, true)) != null)
 803                         {
 804                             right = e;
 805                         }
 806                         else if ((e = PromoteExpression(left, right.Type, true)) != null)
 807                         {
 808                             left = e;
 809                         }
 810                         else
 811                         {
 812                             throw IncompatibleOperandsError(op.text, left, right, op.pos);
 813                         }
 814                     }
 815                 }
 816                 else
 817                 {
 818                     CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
 819                         op.text, ref left, ref right, op.pos);
 820                 }
 821                 switch (op.id)
 822                 {
 823                     case TokenId.Equal:
 824                     case TokenId.DoubleEqual:
 825                         left = GenerateEqual(left, right);
 826                         break;
 827                     case TokenId.ExclamationEqual:
 828                     case TokenId.LessGreater:
 829                         left = GenerateNotEqual(left, right);
 830                         break;
 831                     case TokenId.GreaterThan:
 832                         left = GenerateGreaterThan(left, right);
 833                         break;
 834                     case TokenId.GreaterThanEqual:
 835                         left = GenerateGreaterThanEqual(left, right);
 836                         break;
 837                     case TokenId.LessThan:
 838                         left = GenerateLessThan(left, right);
 839                         break;
 840                     case TokenId.LessThanEqual:
 841                         left = GenerateLessThanEqual(left, right);
 842                         break;
 843                 }
 844             }
 845             return left;
 846         }
 847
 848         // +, -, & operators
 849         Expression ParseAdditive()
 850         {
 851             Expression left = ParseMultiplicative();
 852             while (token.id == TokenId.Plus || token.id == TokenId.Minus ||
 853                 token.id == TokenId.Amphersand)
 854             {
 855                 Token op = token;
 856                 NextToken();
 857                 Expression right = ParseMultiplicative();
 858                 switch (op.id)
 859                 {
 860                     case TokenId.Plus:
 861                         if (left.Type == typeof(string) || right.Type == typeof(string))
 862                             goto case TokenId.Amphersand;
 863                         CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos);
 864                         left = GenerateAdd(left, right);
 865                         break;
 866                     case TokenId.Minus:
 867                         CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos);
 868                         left = GenerateSubtract(left, right);
 869                         break;
 870                     case TokenId.Amphersand:
 871                         left = GenerateStringConcat(left, right);
 872                         break;
 873                 }
 874             }
 875             return left;
 876         }
 877
 878         // *, /, %, mod operators
 879         Expression ParseMultiplicative()
 880         {
 881             Expression left = ParseUnary();
 882             while (token.id == TokenId.Asterisk || token.id == TokenId.Slash ||
 883                 token.id == TokenId.Percent || TokenIdentifierIs("mod"))
 884             {
 885                 Token op = token;
 886                 NextToken();
 887                 Expression right = ParseUnary();
 888                 CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos);
 889                 switch (op.id)
 890                 {
 891                     case TokenId.Asterisk:
 892                         left = Expression.Multiply(left, right);
 893                         break;
 894                     case TokenId.Slash:
 895                         left = Expression.Divide(left, right);
 896                         break;
 897                     case TokenId.Percent:
 898                     case TokenId.Identifier:
 899                         left = Expression.Modulo(left, right);
 900                         break;
 901                 }
 902             }
 903             return left;
 904         }
 905
 906         // -, !, not unary operators
 907         Expression ParseUnary()
 908         {
 909             if (token.id == TokenId.Minus || token.id == TokenId.Exclamation ||
 910                 TokenIdentifierIs("not"))
 911             {
 912                 Token op = token;
 913                 NextToken();
 914                 if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral ||
 915                     token.id == TokenId.RealLiteral))
 916                 {
 917                     token.text = "-" + token.text;
 918                     token.pos = op.pos;
 919                     return ParsePrimary();
 920                 }
 921                 Expression expr = ParseUnary();
 922                 if (op.id == TokenId.Minus)
 923                 {
 924                     CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos);
 925                     expr = Expression.Negate(expr);
 926                 }
 927                 else
 928                 {
 929                     CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos);
 930                     expr = Expression.Not(expr);
 931                 }
 932                 return expr;
 933             }
 934             return ParsePrimary();
 935         }
 936
 937         Expression ParsePrimary()
 938         {
 939             Expression expr = ParsePrimaryStart();
 940             while (true)
 941             {
 942                 if (token.id == TokenId.Dot)
 943                 {
 944                     NextToken();
 945                     expr = ParseMemberAccess(null, expr);
 946                 }
 947                 else if (token.id == TokenId.OpenBracket)
 948                 {
 949                     expr = ParseElementAccess(expr);
 950                 }
 951                 else
 952                 {
 953                     break;
 954                 }
 955             }
 956             return expr;
 957         }
 958
 959         Expression ParsePrimaryStart()
 960         {
 961             switch (token.id)
 962             {
 963                 case TokenId.Identifier:
 964                     return ParseIdentifier();
 965                 case TokenId.StringLiteral:
 966                     return ParseStringLiteral();
 967                 case TokenId.IntegerLiteral:
 968                     return ParseIntegerLiteral();
 969                 case TokenId.RealLiteral:
 970                     return ParseRealLiteral();
 971                 case TokenId.OpenParen:
 972                     return ParseParenExpression();
 973                 default:
 974                     throw ParseError(Res.ExpressionExpected);
 975             }
 976         }
 977
 978         Expression ParseStringLiteral()
 979         {
 980             ValidateToken(TokenId.StringLiteral);
 981             char quote = token.text[0];
 982             string s = token.text.Substring(1, token.text.Length - 2);
 983             int start = 0;
 984             while (true)
 985             {
 986                 int i = s.IndexOf(quote, start);
 987                 if (i < 0) break;
 988                 s = s.Remove(i, 1);
 989                 start = i + 1;
 990             }
 991             if (quote == ‘\‘‘)
 992             {
 993                 if (s.Length != 1)
 994                     throw ParseError(Res.InvalidCharacterLiteral);
 995                 NextToken();
 996                 return CreateLiteral(s[0], s);
 997             }
 998             NextToken();
 999             return CreateLiteral(s, s);
1000         }
1001
1002         Expression ParseIntegerLiteral()
1003         {
1004             ValidateToken(TokenId.IntegerLiteral);
1005             string text = token.text;
1006             if (text[0] != ‘-‘)
1007             {
1008                 ulong value;
1009                 if (!UInt64.TryParse(text, out value))
1010                     throw ParseError(Res.InvalidIntegerLiteral, text);
1011                 NextToken();
1012                 if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text);
1013                 if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text);
1014                 if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text);
1015                 return CreateLiteral(value, text);
1016             }
1017             else
1018             {
1019                 long value;
1020                 if (!Int64.TryParse(text, out value))
1021                     throw ParseError(Res.InvalidIntegerLiteral, text);
1022                 NextToken();
1023                 if (value >= Int32.MinValue && value <= Int32.MaxValue)
1024                     return CreateLiteral((int)value, text);
1025                 return CreateLiteral(value, text);
1026             }
1027         }
1028
1029         Expression ParseRealLiteral()
1030         {
1031             ValidateToken(TokenId.RealLiteral);
1032             string text = token.text;
1033             object value = null;
1034             char last = text[text.Length - 1];
1035             if (last == ‘F‘ || last == ‘f‘)
1036             {
1037                 float f;
1038                 if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f;
1039             }
1040             else
1041             {
1042                 double d;
1043                 if (Double.TryParse(text, out d)) value = d;
1044             }
1045             if (value == null) throw ParseError(Res.InvalidRealLiteral, text);
1046             NextToken();
1047             return CreateLiteral(value, text);
1048         }
1049
1050         Expression CreateLiteral(object value, string text)
1051         {
1052             ConstantExpression expr = Expression.Constant(value);
1053             literals.Add(expr, text);
1054             return expr;
1055         }
1056
1057         Expression ParseParenExpression()
1058         {
1059             ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
1060             NextToken();
1061             Expression e = ParseExpression();
1062             ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected);
1063             NextToken();
1064             return e;
1065         }
1066
1067         Expression ParseIdentifier()
1068         {
1069             ValidateToken(TokenId.Identifier);
1070             object value;
1071             if (keywords.TryGetValue(token.text, out value))
1072             {
1073                 if (value is Type) return ParseTypeAccess((Type)value);
1074                 if (value == (object)keywordIt) return ParseIt();
1075                 if (value == (object)keywordIif) return ParseIif();
1076                 if (value == (object)keywordNew) return ParseNew();
1077                 NextToken();
1078                 return (Expression)value;
1079             }
1080             if (symbols.TryGetValue(token.text, out value) ||
1081                 externals != null && externals.TryGetValue(token.text, out value))
1082             {
1083                 Expression expr = value as Expression;
1084                 if (expr == null)
1085                 {
1086                     expr = Expression.Constant(value);
1087                 }
1088                 else
1089                 {
1090                     LambdaExpression lambda = expr as LambdaExpression;
1091                     if (lambda != null) return ParseLambdaInvocation(lambda);
1092                 }
1093                 NextToken();
1094                 return expr;
1095             }
1096             if (it != null) return ParseMemberAccess(null, it);
1097             throw ParseError(Res.UnknownIdentifier, token.text);
1098         }
1099
1100         Expression ParseIt()
1101         {
1102             if (it == null)
1103                 throw ParseError(Res.NoItInScope);
1104             NextToken();
1105             return it;
1106         }
1107
1108         Expression ParseIif()
1109         {
1110             int errorPos = token.pos;
1111             NextToken();
1112             Expression[] args = ParseArgumentList();
1113             if (args.Length != 3)
1114                 throw ParseError(errorPos, Res.IifRequiresThreeArgs);
1115             return GenerateConditional(args[0], args[1], args[2], errorPos);
1116         }
1117
1118         Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)
1119         {
1120             if (test.Type != typeof(bool))
1121                 throw ParseError(errorPos, Res.FirstExprMustBeBool);
1122             if (expr1.Type != expr2.Type)
1123             {
1124                 Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;
1125                 Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;
1126                 if (expr1as2 != null && expr2as1 == null)
1127                 {
1128                     expr1 = expr1as2;
1129                 }
1130                 else if (expr2as1 != null && expr1as2 == null)
1131                 {
1132                     expr2 = expr2as1;
1133                 }
1134                 else
1135                 {
1136                     string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null";
1137                     string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null";
1138                     if (expr1as2 != null && expr2as1 != null)
1139                         throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2);
1140                     throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2);
1141                 }
1142             }
1143             return Expression.Condition(test, expr1, expr2);
1144         }
1145
1146         Expression ParseNew()
1147         {
1148             NextToken();
1149             ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
1150             NextToken();
1151             List<DynamicProperty> properties = new List<DynamicProperty>();
1152             List<Expression> expressions = new List<Expression>();
1153             while (true)
1154             {
1155                 int exprPos = token.pos;
1156                 Expression expr = ParseExpression();
1157                 string propName;
1158                 if (TokenIdentifierIs("as"))
1159                 {
1160                     NextToken();
1161                     propName = GetIdentifier();
1162                     NextToken();
1163                 }
1164                 else
1165                 {
1166                     MemberExpression me = expr as MemberExpression;
1167                     if (me == null) throw ParseError(exprPos, Res.MissingAsClause);
1168                     propName = me.Member.Name;
1169                 }
1170                 expressions.Add(expr);
1171                 properties.Add(new DynamicProperty(propName, expr.Type));
1172                 if (token.id != TokenId.Comma) break;
1173                 NextToken();
1174             }
1175             ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
1176             NextToken();
1177             Type type = DynamicExpression.CreateClass(properties);
1178             MemberBinding[] bindings = new MemberBinding[properties.Count];
1179             for (int i = 0; i < bindings.Length; i++)
1180                 bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
1181             return Expression.MemberInit(Expression.New(type), bindings);
1182         }
1183
1184         Expression ParseLambdaInvocation(LambdaExpression lambda)
1185         {
1186             int errorPos = token.pos;
1187             NextToken();
1188             Expression[] args = ParseArgumentList();
1189             MethodBase method;
1190             if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1)
1191                 throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda);
1192             return Expression.Invoke(lambda, args);
1193         }
1194
1195         Expression ParseTypeAccess(Type type)
1196         {
1197             int errorPos = token.pos;
1198             NextToken();
1199             if (token.id == TokenId.Question)
1200             {
1201                 if (!type.IsValueType || IsNullableType(type))
1202                     throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type));
1203                 type = typeof(Nullable<>).MakeGenericType(type);
1204                 NextToken();
1205             }
1206             if (token.id == TokenId.OpenParen)
1207             {
1208                 Expression[] args = ParseArgumentList();
1209                 MethodBase method;
1210                 switch (FindBestMethod(type.GetConstructors(), args, out method))
1211                 {
1212                     case 0:
1213                         if (args.Length == 1)
1214                             return GenerateConversion(args[0], type, errorPos);
1215                         throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type));
1216                     case 1:
1217                         return Expression.New((ConstructorInfo)method, args);
1218                     default:
1219                         throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type));
1220                 }
1221             }
1222             ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected);
1223             NextToken();
1224             return ParseMemberAccess(type, null);
1225         }
1226
1227         Expression GenerateConversion(Expression expr, Type type, int errorPos)
1228         {
1229             Type exprType = expr.Type;
1230             if (exprType == type) return expr;
1231             if (exprType.IsValueType && type.IsValueType)
1232             {
1233                 if ((IsNullableType(exprType) || IsNullableType(type)) &&
1234                     GetNonNullableType(exprType) == GetNonNullableType(type))
1235                     return Expression.Convert(expr, type);
1236                 if ((IsNumericType(exprType) || IsEnumType(exprType)) &&
1237                     (IsNumericType(type)) || IsEnumType(type))
1238                     return Expression.ConvertChecked(expr, type);
1239             }
1240             if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||
1241                 exprType.IsInterface || type.IsInterface)
1242                 return Expression.Convert(expr, type);
1243             throw ParseError(errorPos, Res.CannotConvertValue,
1244                 GetTypeName(exprType), GetTypeName(type));
1245         }
1246
1247         Expression ParseMemberAccess(Type type, Expression instance)
1248         {
1249             if (instance != null) type = instance.Type;
1250             int errorPos = token.pos;
1251             string id = GetIdentifier();
1252             NextToken();
1253             if (token.id == TokenId.OpenParen)
1254             {
1255                 if (instance != null && type != typeof(string))
1256                 {
1257                     Type enumerableType = FindGenericType(typeof(IEnumerable<>), type);
1258                     if (enumerableType != null)
1259                     {
1260                         Type elementType = enumerableType.GetGenericArguments()[0];
1261                         return ParseAggregate(instance, elementType, id, errorPos);
1262                     }
1263                 }
1264                 Expression[] args = ParseArgumentList();
1265                 MethodBase mb;
1266                 switch (FindMethod(type, id, instance == null, args, out mb))
1267                 {
1268                     case 0:
1269                         throw ParseError(errorPos, Res.NoApplicableMethod,
1270                             id, GetTypeName(type));
1271                     case 1:
1272                         MethodInfo method = (MethodInfo)mb;
1273                         if (!IsPredefinedType(method.DeclaringType))
1274                             throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
1275                         if (method.ReturnType == typeof(void))
1276                             throw ParseError(errorPos, Res.MethodIsVoid,
1277                                 id, GetTypeName(method.DeclaringType));
1278                         return Expression.Call(instance, (MethodInfo)method, args);
1279                     default:
1280                         throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
1281                             id, GetTypeName(type));
1282                 }
1283             }
1284             else
1285             {
1286                 MemberInfo member = FindPropertyOrField(type, id, instance == null);
1287                 if (member == null)
1288                     throw ParseError(errorPos, Res.UnknownPropertyOrField,
1289                         id, GetTypeName(type));
1290                 return member is PropertyInfo ?
1291                     Expression.Property(instance, (PropertyInfo)member) :
1292                     Expression.Field(instance, (FieldInfo)member);
1293             }
1294         }
1295
1296         static Type FindGenericType(Type generic, Type type)
1297         {
1298             while (type != null && type != typeof(object))
1299             {
1300                 if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type;
1301                 if (generic.IsInterface)
1302                 {
1303                     foreach (Type intfType in type.GetInterfaces())
1304                     {
1305                         Type found = FindGenericType(generic, intfType);
1306                         if (found != null) return found;
1307                     }
1308                 }
1309                 type = type.BaseType;
1310             }
1311             return null;
1312         }
1313
1314         Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
1315         {
1316             ParameterExpression outerIt = it;
1317             ParameterExpression innerIt = Expression.Parameter(elementType, "");
1318             it = innerIt;
1319             Expression[] args = ParseArgumentList();
1320             it = outerIt;
1321             MethodBase signature;
1322             if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)
1323                 throw ParseError(errorPos, Res.NoApplicableAggregate, methodName);
1324             Type[] typeArgs;
1325             if (signature.Name == "Min" || signature.Name == "Max")
1326             {
1327                 typeArgs = new Type[] { elementType, args[0].Type };
1328             }
1329             else
1330             {
1331                 typeArgs = new Type[] { elementType };
1332             }
1333             if (args.Length == 0)
1334             {
1335                 args = new Expression[] { instance };
1336             }
1337             else
1338             {
1339                 args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) };
1340             }
1341             return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);
1342         }
1343
1344         Expression[] ParseArgumentList()
1345         {
1346             ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
1347             NextToken();
1348             Expression[] args = token.id != TokenId.CloseParen ? ParseArguments() : new Expression[0];
1349             ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
1350             NextToken();
1351             return args;
1352         }
1353
1354         Expression[] ParseArguments()
1355         {
1356             List<Expression> argList = new List<Expression>();
1357             while (true)
1358             {
1359                 argList.Add(ParseExpression());
1360                 if (token.id != TokenId.Comma) break;
1361                 NextToken();
1362             }
1363             return argList.ToArray();
1364         }
1365
1366         Expression ParseElementAccess(Expression expr)
1367         {
1368             int errorPos = token.pos;
1369             ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);
1370             NextToken();
1371             Expression[] args = ParseArguments();
1372             ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);
1373             NextToken();
1374             if (expr.Type.IsArray)
1375             {
1376                 if (expr.Type.GetArrayRank() != 1 || args.Length != 1)
1377                     throw ParseError(errorPos, Res.CannotIndexMultiDimArray);
1378                 Expression index = PromoteExpression(args[0], typeof(int), true);
1379                 if (index == null)
1380                     throw ParseError(errorPos, Res.InvalidIndex);
1381                 return Expression.ArrayIndex(expr, index);
1382             }
1383             else
1384             {
1385                 MethodBase mb;
1386                 switch (FindIndexer(expr.Type, args, out mb))
1387                 {
1388                     case 0:
1389                         throw ParseError(errorPos, Res.NoApplicableIndexer,
1390                             GetTypeName(expr.Type));
1391                     case 1:
1392                         return Expression.Call(expr, (MethodInfo)mb, args);
1393                     default:
1394                         throw ParseError(errorPos, Res.AmbiguousIndexerInvocation,
1395                             GetTypeName(expr.Type));
1396                 }
1397             }
1398         }
1399
1400         static bool IsPredefinedType(Type type)
1401         {
1402             foreach (Type t in predefinedTypes) if (t == type) return true;
1403             return false;
1404         }
1405
1406         static bool IsNullableType(Type type)
1407         {
1408             return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
1409         }
1410
1411         static Type GetNonNullableType(Type type)
1412         {
1413             return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
1414         }
1415
1416         static string GetTypeName(Type type)
1417         {
1418             Type baseType = GetNonNullableType(type);
1419             string s = baseType.Name;
1420             if (type != baseType) s += ‘?‘;
1421             return s;
1422         }
1423
1424         static bool IsNumericType(Type type)
1425         {
1426             return GetNumericTypeKind(type) != 0;
1427         }
1428
1429         static bool IsSignedIntegralType(Type type)
1430         {
1431             return GetNumericTypeKind(type) == 2;
1432         }
1433
1434         static bool IsUnsignedIntegralType(Type type)
1435         {
1436             return GetNumericTypeKind(type) == 3;
1437         }
1438
1439         static int GetNumericTypeKind(Type type)
1440         {
1441             type = GetNonNullableType(type);
1442             if (type.IsEnum) return 0;
1443             switch (Type.GetTypeCode(type))
1444             {
1445                 case TypeCode.Char:
1446                 case TypeCode.Single:
1447                 case TypeCode.Double:
1448                 case TypeCode.Decimal:
1449                     return 1;
1450                 case TypeCode.SByte:
1451                 case TypeCode.Int16:
1452                 case TypeCode.Int32:
1453                 case TypeCode.Int64:
1454                     return 2;
1455                 case TypeCode.Byte:
1456                 case TypeCode.UInt16:
1457                 case TypeCode.UInt32:
1458                 case TypeCode.UInt64:
1459                     return 3;
1460                 default:
1461                     return 0;
1462             }
1463         }
1464
1465         static bool IsEnumType(Type type)
1466         {
1467             return GetNonNullableType(type).IsEnum;
1468         }
1469
1470         void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
1471         {
1472             Expression[] args = new Expression[] { expr };
1473             MethodBase method;
1474             if (FindMethod(signatures, "F", false, args, out method) != 1)
1475                 throw ParseError(errorPos, Res.IncompatibleOperand,
1476                     opName, GetTypeName(args[0].Type));
1477             expr = args[0];
1478         }
1479
1480         void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
1481         {
1482             Expression[] args = new Expression[] { left, right };
1483             MethodBase method;
1484             if (FindMethod(signatures, "F", false, args, out method) != 1)
1485                 throw IncompatibleOperandsError(opName, left, right, errorPos);
1486             left = args[0];
1487             right = args[1];
1488         }
1489
1490         Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
1491         {
1492             return ParseError(pos, Res.IncompatibleOperands,
1493                 opName, GetTypeName(left.Type), GetTypeName(right.Type));
1494         }
1495
1496         MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
1497         {
1498             BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
1499                 (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
1500             foreach (Type t in SelfAndBaseTypes(type))
1501             {
1502                 MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
1503                     flags, Type.FilterNameIgnoreCase, memberName);
1504                 if (members.Length != 0) return members[0];
1505             }
1506             return null;
1507         }
1508
1509         int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
1510         {
1511             BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
1512                 (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
1513             foreach (Type t in SelfAndBaseTypes(type))
1514             {
1515                 MemberInfo[] members = t.FindMembers(MemberTypes.Method,
1516                     flags, Type.FilterNameIgnoreCase, methodName);
1517                 int count = FindBestMethod(members.Cast<MethodBase>(), args, out method);
1518                 if (count != 0) return count;
1519             }
1520             method = null;
1521             return 0;
1522         }
1523
1524         int FindIndexer(Type type, Expression[] args, out MethodBase method)
1525         {
1526             foreach (Type t in SelfAndBaseTypes(type))
1527             {
1528                 MemberInfo[] members = t.GetDefaultMembers();
1529                 if (members.Length != 0)
1530                 {
1531                     IEnumerable<MethodBase> methods = members.
1532                         OfType<PropertyInfo>().
1533                         Select(p => (MethodBase)p.GetGetMethod()).
1534                         Where(m => m != null);
1535                     int count = FindBestMethod(methods, args, out method);
1536                     if (count != 0) return count;
1537                 }
1538             }
1539             method = null;
1540             return 0;
1541         }
1542
1543         static IEnumerable<Type> SelfAndBaseTypes(Type type)
1544         {
1545             if (type.IsInterface)
1546             {
1547                 List<Type> types = new List<Type>();
1548                 AddInterface(types, type);
1549                 return types;
1550             }
1551             return SelfAndBaseClasses(type);
1552         }
1553
1554         static IEnumerable<Type> SelfAndBaseClasses(Type type)
1555         {
1556             while (type != null)
1557             {
1558                 yield return type;
1559                 type = type.BaseType;
1560             }
1561         }
1562
1563         static void AddInterface(List<Type> types, Type type)
1564         {
1565             if (!types.Contains(type))
1566             {
1567                 types.Add(type);
1568                 foreach (Type t in type.GetInterfaces()) AddInterface(types, t);
1569             }
1570         }
1571
1572         class MethodData
1573         {
1574             public MethodBase MethodBase;
1575             public ParameterInfo[] Parameters;
1576             public Expression[] Args;
1577         }
1578
1579         int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)
1580         {
1581             MethodData[] applicable = methods.
1582                 Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).
1583                 Where(m => IsApplicable(m, args)).
1584                 ToArray();
1585             if (applicable.Length > 1)
1586             {
1587                 applicable = applicable.
1588                     Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
1589                     ToArray();
1590             }
1591             if (applicable.Length == 1)
1592             {
1593                 MethodData md = applicable[0];
1594                 for (int i = 0; i < args.Length; i++) args[i] = md.Args[i];
1595                 method = md.MethodBase;
1596             }
1597             else
1598             {
1599                 method = null;
1600             }
1601             return applicable.Length;
1602         }
1603
1604         bool IsApplicable(MethodData method, Expression[] args)
1605         {
1606             if (method.Parameters.Length != args.Length) return false;
1607             Expression[] promotedArgs = new Expression[args.Length];
1608             for (int i = 0; i < args.Length; i++)
1609             {
1610                 ParameterInfo pi = method.Parameters[i];
1611                 if (pi.IsOut) return false;
1612                 Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
1613                 if (promoted == null) return false;
1614                 promotedArgs[i] = promoted;
1615             }
1616             method.Args = promotedArgs;
1617             return true;
1618         }
1619
1620         Expression PromoteExpression(Expression expr, Type type, bool exact)
1621         {
1622             if (expr.Type == type) return expr;
1623             if (expr is ConstantExpression)
1624             {
1625                 ConstantExpression ce = (ConstantExpression)expr;
1626                 if (ce == nullLiteral)
1627                 {
1628                     if (!type.IsValueType || IsNullableType(type))
1629                         return Expression.Constant(null, type);
1630                 }
1631                 else
1632                 {
1633                     string text;
1634                     if (literals.TryGetValue(ce, out text))
1635                     {
1636                         Type target = GetNonNullableType(type);
1637                         Object value = null;
1638                         switch (Type.GetTypeCode(ce.Type))
1639                         {
1640                             case TypeCode.Int32:
1641                             case TypeCode.UInt32:
1642                             case TypeCode.Int64:
1643                             case TypeCode.UInt64:
1644                                 value = ParseNumber(text, target);
1645                                 break;
1646                             case TypeCode.Double:
1647                                 if (target == typeof(decimal)) value = ParseNumber(text, target);
1648                                 break;
1649                             case TypeCode.String:
1650                                 value = ParseEnum(text, target);
1651                                 break;
1652                         }
1653                         if (value != null)
1654                             return Expression.Constant(value, type);
1655                     }
1656                 }
1657             }
1658             if (IsCompatibleWith(expr.Type, type))
1659             {
1660                 if (type.IsValueType || exact) return Expression.Convert(expr, type);
1661                 return expr;
1662             }
1663             return null;
1664         }
1665
1666         static object ParseNumber(string text, Type type)
1667         {
1668             switch (Type.GetTypeCode(GetNonNullableType(type)))
1669             {
1670                 case TypeCode.SByte:
1671                     sbyte sb;
1672                     if (sbyte.TryParse(text, out sb)) return sb;
1673                     break;
1674                 case TypeCode.Byte:
1675                     byte b;
1676                     if (byte.TryParse(text, out b)) return b;
1677                     break;
1678                 case TypeCode.Int16:
1679                     short s;
1680                     if (short.TryParse(text, out s)) return s;
1681                     break;
1682                 case TypeCode.UInt16:
1683                     ushort us;
1684                     if (ushort.TryParse(text, out us)) return us;
1685                     break;
1686                 case TypeCode.Int32:
1687                     int i;
1688                     if (int.TryParse(text, out i)) return i;
1689                     break;
1690                 case TypeCode.UInt32:
1691                     uint ui;
1692                     if (uint.TryParse(text, out ui)) return ui;
1693                     break;
1694                 case TypeCode.Int64:
1695                     long l;
1696                     if (long.TryParse(text, out l)) return l;
1697                     break;
1698                 case TypeCode.UInt64:
1699                     ulong ul;
1700                     if (ulong.TryParse(text, out ul)) return ul;
1701                     break;
1702                 case TypeCode.Single:
1703                     float f;
1704                     if (float.TryParse(text, out f)) return f;
1705                     break;
1706                 case TypeCode.Double:
1707                     double d;
1708                     if (double.TryParse(text, out d)) return d;
1709                     break;
1710                 case TypeCode.Decimal:
1711                     decimal e;
1712                     if (decimal.TryParse(text, out e)) return e;
1713                     break;
1714             }
1715             return null;
1716         }
1717
1718         static object ParseEnum(string name, Type type)
1719         {
1720             if (type.IsEnum)
1721             {
1722                 MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,
1723                     BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,
1724                     Type.FilterNameIgnoreCase, name);
1725                 if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null);
1726             }
1727             return null;
1728         }
1729
1730         static bool IsCompatibleWith(Type source, Type target)
1731         {
1732             if (source == target) return true;
1733             if (!target.IsValueType) return target.IsAssignableFrom(source);
1734             Type st = GetNonNullableType(source);
1735             Type tt = GetNonNullableType(target);
1736             if (st != source && tt == target) return false;
1737             TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st);
1738             TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt);
1739             switch (sc)
1740             {
1741                 case TypeCode.SByte:
1742                     switch (tc)
1743                     {
1744                         case TypeCode.SByte:
1745                         case TypeCode.Int16:
1746                         case TypeCode.Int32:
1747                         case TypeCode.Int64:
1748                         case TypeCode.Single:
1749                         case TypeCode.Double:
1750                         case TypeCode.Decimal:
1751                             return true;
1752                     }
1753                     break;
1754                 case TypeCode.Byte:
1755                     switch (tc)
1756                     {
1757                         case TypeCode.Byte:
1758                         case TypeCode.Int16:
1759                         case TypeCode.UInt16:
1760                         case TypeCode.Int32:
1761                         case TypeCode.UInt32:
1762                         case TypeCode.Int64:
1763                         case TypeCode.UInt64:
1764                         case TypeCode.Single:
1765                         case TypeCode.Double:
1766                         case TypeCode.Decimal:
1767                             return true;
1768                     }
1769                     break;
1770                 case TypeCode.Int16:
1771                     switch (tc)
1772                     {
1773                         case TypeCode.Int16:
1774                         case TypeCode.Int32:
1775                         case TypeCode.Int64:
1776                         case TypeCode.Single:
1777                         case TypeCode.Double:
1778                         case TypeCode.Decimal:
1779                             return true;
1780                     }
1781                     break;
1782                 case TypeCode.UInt16:
1783                     switch (tc)
1784                     {
1785                         case TypeCode.UInt16:
1786                         case TypeCode.Int32:
1787                         case TypeCode.UInt32:
1788                         case TypeCode.Int64:
1789                         case TypeCode.UInt64:
1790                         case TypeCode.Single:
1791                         case TypeCode.Double:
1792                         case TypeCode.Decimal:
1793                             return true;
1794                     }
1795                     break;
1796                 case TypeCode.Int32:
1797                     switch (tc)
1798                     {
1799                         case TypeCode.Int32:
1800                         case TypeCode.Int64:
1801                         case TypeCode.Single:
1802                         case TypeCode.Double:
1803                         case TypeCode.Decimal:
1804                             return true;
1805                     }
1806                     break;
1807                 case TypeCode.UInt32:
1808                     switch (tc)
1809                     {
1810                         case TypeCode.UInt32:
1811                         case TypeCode.Int64:
1812                         case TypeCode.UInt64:
1813                         case TypeCode.Single:
1814                         case TypeCode.Double:
1815                         case TypeCode.Decimal:
1816                             return true;
1817                     }
1818                     break;
1819                 case TypeCode.Int64:
1820                     switch (tc)
1821                     {
1822                         case TypeCode.Int64:
1823                         case TypeCode.Single:
1824                         case TypeCode.Double:
1825                         case TypeCode.Decimal:
1826                             return true;
1827                     }
1828                     break;
1829                 case TypeCode.UInt64:
1830                     switch (tc)
1831                     {
1832                         case TypeCode.UInt64:
1833                         case TypeCode.Single:
1834                         case TypeCode.Double:
1835                         case TypeCode.Decimal:
1836                             return true;
1837                     }
1838                     break;
1839                 case TypeCode.Single:
1840                     switch (tc)
1841                     {
1842                         case TypeCode.Single:
1843                         case TypeCode.Double:
1844                             return true;
1845                     }
1846                     break;
1847                 default:
1848                     if (st == tt) return true;
1849                     break;
1850             }
1851             return false;
1852         }
1853
1854         static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
1855         {
1856             bool better = false;
1857             for (int i = 0; i < args.Length; i++)
1858             {
1859                 int c = CompareConversions(args[i].Type,
1860                     m1.Parameters[i].ParameterType,
1861                     m2.Parameters[i].ParameterType);
1862                 if (c < 0) return false;
1863                 if (c > 0) better = true;
1864             }
1865             return better;
1866         }
1867
1868         // Return 1 if s -> t1 is a better conversion than s -> t2
1869         // Return -1 if s -> t2 is a better conversion than s -> t1
1870         // Return 0 if neither conversion is better
1871         static int CompareConversions(Type s, Type t1, Type t2)
1872         {
1873             if (t1 == t2) return 0;
1874             if (s == t1) return 1;
1875             if (s == t2) return -1;
1876             bool t1t2 = IsCompatibleWith(t1, t2);
1877             bool t2t1 = IsCompatibleWith(t2, t1);
1878             if (t1t2 && !t2t1) return 1;
1879             if (t2t1 && !t1t2) return -1;
1880             if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1;
1881             if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1;
1882             return 0;
1883         }
1884
1885         Expression GenerateEqual(Expression left, Expression right)
1886         {
1887             return Expression.Equal(left, right);
1888         }
1889
1890         Expression GenerateNotEqual(Expression left, Expression right)
1891         {
1892             return Expression.NotEqual(left, right);
1893         }
1894
1895         Expression GenerateGreaterThan(Expression left, Expression right)
1896         {
1897             if (left.Type == typeof(string))
1898             {
1899                 return Expression.GreaterThan(
1900                     GenerateStaticMethodCall("Compare", left, right),
1901                     Expression.Constant(0)
1902                 );
1903             }
1904             return Expression.GreaterThan(left, right);
1905         }
1906
1907         Expression GenerateGreaterThanEqual(Expression left, Expression right)
1908         {
1909             if (left.Type == typeof(string))
1910             {
1911                 return Expression.GreaterThanOrEqual(
1912                     GenerateStaticMethodCall("Compare", left, right),
1913                     Expression.Constant(0)
1914                 );
1915             }
1916             return Expression.GreaterThanOrEqual(left, right);
1917         }
1918
1919         Expression GenerateLessThan(Expression left, Expression right)
1920         {
1921             if (left.Type == typeof(string))
1922             {
1923                 return Expression.LessThan(
1924                     GenerateStaticMethodCall("Compare", left, right),
1925                     Expression.Constant(0)
1926                 );
1927             }
1928             return Expression.LessThan(left, right);
1929         }
1930
1931         Expression GenerateLessThanEqual(Expression left, Expression right)
1932         {
1933             if (left.Type == typeof(string))
1934             {
1935                 return Expression.LessThanOrEqual(
1936                     GenerateStaticMethodCall("Compare", left, right),
1937                     Expression.Constant(0)
1938                 );
1939             }
1940             return Expression.LessThanOrEqual(left, right);
1941         }
1942
1943         Expression GenerateAdd(Expression left, Expression right)
1944         {
1945             if (left.Type == typeof(string) && right.Type == typeof(string))
1946             {
1947                 return GenerateStaticMethodCall("Concat", left, right);
1948             }
1949             return Expression.Add(left, right);
1950         }
1951
1952         Expression GenerateSubtract(Expression left, Expression right)
1953         {
1954             return Expression.Subtract(left, right);
1955         }
1956
1957         Expression GenerateStringConcat(Expression left, Expression right)
1958         {
1959             return Expression.Call(
1960                 null,
1961                 typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
1962                 new[] { left, right });
1963         }
1964
1965         MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
1966         {
1967             return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
1968         }
1969
1970         Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
1971         {
1972             return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });
1973         }
1974
1975         void SetTextPos(int pos)
1976         {
1977             textPos = pos;
1978             ch = textPos < textLen ? text[textPos] : ‘\0‘;
1979         }
1980
1981         void NextChar()
1982         {
1983             if (textPos < textLen) textPos++;
1984             ch = textPos < textLen ? text[textPos] : ‘\0‘;
1985         }
1986
1987         void NextToken()
1988         {
1989             while (Char.IsWhiteSpace(ch)) NextChar();
1990             TokenId t;
1991             int tokenPos = textPos;
1992             switch (ch)
1993             {
1994                 case ‘!‘:
1995                     NextChar();
1996                     if (ch == ‘=‘)
1997                     {
1998                         NextChar();
1999                         t = TokenId.ExclamationEqual;
2000                     }
2001                     else
2002                     {
2003                         t = TokenId.Exclamation;
2004                     }
2005                     break;
2006                 case ‘%‘:
2007                     NextChar();
2008                     t = TokenId.Percent;
2009                     break;
2010                 case ‘&‘:
2011                     NextChar();
2012                     if (ch == ‘&‘)
2013                     {
2014                         NextChar();
2015                         t = TokenId.DoubleAmphersand;
2016                     }
2017                     else
2018                     {
2019                         t = TokenId.Amphersand;
2020                     }
2021                     break;
2022                 case ‘(‘:
2023                     NextChar();
2024                     t = TokenId.OpenParen;
2025                     break;
2026                 case ‘)‘:
2027                     NextChar();
2028                     t = TokenId.CloseParen;
2029                     break;
2030                 case ‘*‘:
2031                     NextChar();
2032                     t = TokenId.Asterisk;
2033                     break;
2034                 case ‘+‘:
2035                     NextChar();
2036                     t = TokenId.Plus;
2037                     break;
2038                 case ‘,‘:
2039                     NextChar();
2040                     t = TokenId.Comma;
2041                     break;
2042                 case ‘-‘:
2043                     NextChar();
2044                     t = TokenId.Minus;
2045                     break;
2046                 case ‘.‘:
2047                     NextChar();
2048                     t = TokenId.Dot;
2049                     break;
2050                 case ‘/‘:
2051                     NextChar();
2052                     t = TokenId.Slash;
2053                     break;
2054                 case ‘:‘:
2055                     NextChar();
2056                     t = TokenId.Colon;
2057                     break;
2058                 case ‘<‘:
2059                     NextChar();
2060                     if (ch == ‘=‘)
2061                     {
2062                         NextChar();
2063                         t = TokenId.LessThanEqual;
2064                     }
2065                     else if (ch == ‘>‘)
2066                     {
2067                         NextChar();
2068                         t = TokenId.LessGreater;
2069                     }
2070                     else
2071                     {
2072                         t = TokenId.LessThan;
2073                     }
2074                     break;
2075                 case ‘=‘:
2076                     NextChar();
2077                     if (ch == ‘=‘)
2078                     {
2079                         NextChar();
2080                         t = TokenId.DoubleEqual;
2081                     }
2082                     else
2083                     {
2084                         t = TokenId.Equal;
2085                     }
2086                     break;
2087                 case ‘>‘:
2088                     NextChar();
2089                     if (ch == ‘=‘)
2090                     {
2091                         NextChar();
2092                         t = TokenId.GreaterThanEqual;
2093                     }
2094                     else
2095                     {
2096                         t = TokenId.GreaterThan;
2097                     }
2098                     break;
2099                 case ‘?‘:
2100                     NextChar();
2101                     t = TokenId.Question;
2102                     break;
2103                 case ‘[‘:
2104                     NextChar();
2105                     t = TokenId.OpenBracket;
2106                     break;
2107                 case ‘]‘:
2108                     NextChar();
2109                     t = TokenId.CloseBracket;
2110                     break;
2111                 case ‘|‘:
2112                     NextChar();
2113                     if (ch == ‘|‘)
2114                     {
2115                         NextChar();
2116                         t = TokenId.DoubleBar;
2117                     }
2118                     else
2119                     {
2120                         t = TokenId.Bar;
2121                     }
2122                     break;
2123                 case ‘"‘:
2124                 case ‘\‘‘:
2125                     char quote = ch;
2126                     do
2127                     {
2128                         NextChar();
2129                         while (textPos < textLen && ch != quote) NextChar();
2130                         if (textPos == textLen)
2131                             throw ParseError(textPos, Res.UnterminatedStringLiteral);
2132                         NextChar();
2133                     } while (ch == quote);
2134                     t = TokenId.StringLiteral;
2135                     break;
2136                 default:
2137                     if (Char.IsLetter(ch) || ch == ‘@‘ || ch == ‘_‘)
2138                     {
2139                         do
2140                         {
2141                             NextChar();
2142                         } while (Char.IsLetterOrDigit(ch) || ch == ‘_‘);
2143                         t = TokenId.Identifier;
2144                         break;
2145                     }
2146                     if (Char.IsDigit(ch))
2147                     {
2148                         t = TokenId.IntegerLiteral;
2149                         do
2150                         {
2151                             NextChar();
2152                         } while (Char.IsDigit(ch));
2153                         if (ch == ‘.‘)
2154                         {
2155                             t = TokenId.RealLiteral;
2156                             NextChar();
2157                             ValidateDigit();
2158                             do
2159                             {
2160                                 NextChar();
2161                             } while (Char.IsDigit(ch));
2162                         }
2163                         if (ch == ‘E‘ || ch == ‘e‘)
2164                         {
2165                             t = TokenId.RealLiteral;
2166                             NextChar();
2167                             if (ch == ‘+‘ || ch == ‘-‘) NextChar();
2168                             ValidateDigit();
2169                             do
2170                             {
2171                                 NextChar();
2172                             } while (Char.IsDigit(ch));
2173                         }
2174                         if (ch == ‘F‘ || ch == ‘f‘) NextChar();
2175                         break;
2176                     }
2177                     if (textPos == textLen)
2178                     {
2179                         t = TokenId.End;
2180                         break;
2181                     }
2182                     throw ParseError(textPos, Res.InvalidCharacter, ch);
2183             }
2184             token.id = t;
2185             token.text = text.Substring(tokenPos, textPos - tokenPos);
2186             token.pos = tokenPos;
2187         }
2188
2189         bool TokenIdentifierIs(string id)
2190         {
2191             return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase);
2192         }
2193
2194         string GetIdentifier()
2195         {
2196             ValidateToken(TokenId.Identifier, Res.IdentifierExpected);
2197             string id = token.text;
2198             if (id.Length > 1 && id[0] == ‘@‘) id = id.Substring(1);
2199             return id;
2200         }
2201
2202         void ValidateDigit()
2203         {
2204             if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected);
2205         }
2206
2207         void ValidateToken(TokenId t, string errorMessage)
2208         {
2209             if (token.id != t) throw ParseError(errorMessage);
2210         }
2211
2212         void ValidateToken(TokenId t)
2213         {
2214             if (token.id != t) throw ParseError(Res.SyntaxError);
2215         }
2216
2217         Exception ParseError(string format, params object[] args)
2218         {
2219             return ParseError(token.pos, format, args);
2220         }
2221
2222         Exception ParseError(int pos, string format, params object[] args)
2223         {
2224             return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos);
2225         }
2226
2227         static Dictionary<string, object> CreateKeywords()
2228         {
2229             Dictionary<string, object> d = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
2230             d.Add("true", trueLiteral);
2231             d.Add("false", falseLiteral);
2232             d.Add("null", nullLiteral);
2233             d.Add(keywordIt, keywordIt);
2234             d.Add(keywordIif, keywordIif);
2235             d.Add(keywordNew, keywordNew);
2236             foreach (Type type in predefinedTypes) d.Add(type.Name, type);
2237             return d;
2238         }
2239     }
2240
2241     static class Res
2242     {
2243         public const string DuplicateIdentifier = "The identifier ‘{0}‘ was defined more than once";
2244         public const string ExpressionTypeMismatch = "Expression of type ‘{0}‘ expected";
2245         public const string ExpressionExpected = "Expression expected";
2246         public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";
2247         public const string InvalidIntegerLiteral = "Invalid integer literal ‘{0}‘";
2248         public const string InvalidRealLiteral = "Invalid real literal ‘{0}‘";
2249         public const string UnknownIdentifier = "Unknown identifier ‘{0}‘";
2250         public const string NoItInScope = "No ‘it‘ is in scope";
2251         public const string IifRequiresThreeArgs = "The ‘iif‘ function requires three arguments";
2252         public const string FirstExprMustBeBool = "The first expression must be of type ‘Boolean‘";
2253         public const string BothTypesConvertToOther = "Both of the types ‘{0}‘ and ‘{1}‘ convert to the other";
2254         public const string NeitherTypeConvertsToOther = "Neither of the types ‘{0}‘ and ‘{1}‘ converts to the other";
2255         public const string MissingAsClause = "Expression is missing an ‘as‘ clause";
2256         public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression";
2257         public const string TypeHasNoNullableForm = "Type ‘{0}‘ has no nullable form";
2258         public const string NoMatchingConstructor = "No matching constructor in type ‘{0}‘";
2259         public const string AmbiguousConstructorInvocation = "Ambiguous invocation of ‘{0}‘ constructor";
2260         public const string CannotConvertValue = "A value of type ‘{0}‘ cannot be converted to type ‘{1}‘";
2261         public const string NoApplicableMethod = "No applicable method ‘{0}‘ exists in type ‘{1}‘";
2262         public const string MethodsAreInaccessible = "Methods on type ‘{0}‘ are not accessible";
2263         public const string MethodIsVoid = "Method ‘{0}‘ in type ‘{1}‘ does not return a value";
2264         public const string AmbiguousMethodInvocation = "Ambiguous invocation of method ‘{0}‘ in type ‘{1}‘";
2265         public const string UnknownPropertyOrField = "No property or field ‘{0}‘ exists in type ‘{1}‘";
2266         public const string NoApplicableAggregate = "No applicable aggregate method ‘{0}‘ exists";
2267         public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported";
2268         public const string InvalidIndex = "Array index must be an integer expression";
2269         public const string NoApplicableIndexer = "No applicable indexer exists in type ‘{0}‘";
2270         public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type ‘{0}‘";
2271         public const string IncompatibleOperand = "Operator ‘{0}‘ incompatible with operand type ‘{1}‘";
2272         public const string IncompatibleOperands = "Operator ‘{0}‘ incompatible with operand types ‘{1}‘ and ‘{2}‘";
2273         public const string UnterminatedStringLiteral = "Unterminated string literal";
2274         public const string InvalidCharacter = "Syntax error ‘{0}‘";
2275         public const string DigitExpected = "Digit expected";
2276         public const string SyntaxError = "Syntax error";
2277         public const string TokenExpected = "{0} expected";
2278         public const string ParseExceptionFormat = "{0} (at index {1})";
2279         public const string ColonExpected = "‘:‘ expected";
2280         public const string OpenParenExpected = "‘(‘ expected";
2281         public const string CloseParenOrOperatorExpected = "‘)‘ or operator expected";
2282         public const string CloseParenOrCommaExpected = "‘)‘ or ‘,‘ expected";
2283         public const string DotOrOpenParenExpected = "‘.‘ or ‘(‘ expected";
2284         public const string OpenBracketExpected = "‘[‘ expected";
2285         public const string CloseBracketOrCommaExpected = "‘]‘ or ‘,‘ expected";
2286         public const string IdentifierExpected = "Identifier expected";
2287     }
2288 }

DynamicQueryable

var q = collection.AsQueryable<Customer>()
     .Where(String.Format("CustomerName = \"{0}\" And Tel != \"\"", searchWord))
     .OrderBy("Tel");
return q.GetPagingList<Customer>(pagingInfo);

我很少用Linq不知道大家都用什么样的方法,有更好的方法可以给我留言~

时间: 2024-10-25 18:20:33

Linq 动态查询排序的相关文章

EntityFramework.Extended 实现Linq 动态查询和动态条件

找了很久的的关于EF 实现动态查询及条件,最后发现使用EntityFramework.Extended最为简单. 1. 引用EntityFramework.Extended (自己在Nuget下载) using EntityFramework.Extensions;using System.Linq.Dynamic; 2. 代码如下: ERPContent erp = new ERPContent(); string s = "new ( state_key , state_name , act

Linq动态查询简易解决之道(原创)

因为项目需要使用Linq来查询数据,但是在多条件查询时,需要使用一大堆if(...!=string.empty)等判断条件感觉不是很优雅.网上搜索以下,大概找到了两种办法,一种是老外写的一个类,感觉用着麻烦:还有就是提供一扩展个方法,参数为某个类型,当调用该方法时,用反射去遍历这个类型的属性,再拿动态查询参数和属性值去比较,然后构建动态lambda表达式,这个也有缺陷,就是需要遍历类型的所有属性,而且构建lambda表达式只能构建==类型表达式,有局限性.所以自己琢磨了一个办法,调用时只需一行代

zTree初体验--MVC linq动态多条件OR查询

工作需要,使用zTree实现了一个点击显示下拉复选框列表选中项作为查询条件的功能.简单记录下菜鸟级开发历程. zTree:是一个依靠jQuery实现的多功能树控件.通过简单引用配置就可使用. 具体使用: (1).脚本.样式引用 注意:引用顺序,zTree.js一定放最后. <link rel="stylesheet" href="@Url.Content("~/Scripts/jquery.plugins/zTree/zTreeStyle.css")

LINQ体验(17)——LINQ to SQL语句之动态查询

高级特性 本文介绍LINQ的高级特性,其包括大家都关心的动态查询的用法,另外简单提下ID标识这个知识. 动态查询 有这样一个场景:应用程序可能会提供一个用户界面,用户可以使用该用户界面指定一个或多个谓词来筛选数据.这种情况在编译时不知道查询的细节,动态查询将十分有用. 在LINQ中,Lambda表达式是许多标准查询运算符的基础,编译器创建lambda表达式以捕获基础查询方法(例如 Where.Select.Order By.Take While 以及其他方法)中定义的计算.表达式目录树用于针对数

linq之InnerJoin和LeftJoin以及封装动态查询条件版本

Linq的出现,使数据集的处理显得愈来愈简便.很多时候对于本地数据集的处理,脑海中的第一反应,即尝试使用Linq来实现.诸如DataTable的innerJoin以及leftJoin等操作,很多时候我们一接到类似的需求,立马便动手,诸如以下demo: 一.InnerJoin 1 var qMyMx = from mxDr in _dtJgTcDetail.Rows.Cast<DataRow>().Where(drMx => id.Equals(drMx["TCID"]

Linq To Sql进阶系列(六)用object的动态查询与保存log篇

动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动态查询呢? 1,用object的查询是什么?我们可以简单的举这么一个例子.我们到公安局查找一个人.首先,我们会给出他的一些特征,比如,身高多少,年龄多少,性别,民族等.那么,我们把这个人的一些特征输入电脑.我们希望,电脑能给我们返回这个人的信息.而实际上,有相同特征的人太多了,常常返回一个集合.那让

Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询

原文:Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询 如果允许在UI层直接访问Linq to Sql的DataContext,可以省去很多问题,譬如在处理多表join的时候,我们使用var来定义L2S查询,让编译器自动推断变量的具体类型(IQueryable<匿名类型>),并提供友好的智能提示:而且可以充分应用L2S的延迟加载特性,来进行动态查询.但如果我们希望将业务逻辑放在一个独立的层中(譬如封装在远程的WCF应用中),又希望在逻辑层应用Linq to sql,则情

Linq to Sql : 动态构造Expression进行动态查询

原文:Linq to Sql : 动态构造Expression进行动态查询 前一篇在介绍动态查询时,提到一个问题:如何根据用户的输入条件,动态构造这个过滤条件表达式呢?Expression<Func<ProductExt, bool>> predicate t => t.ProductName.Contains("che") && t.UnitPrice >= 22; 理想情况下,我希望可以像下面这样来构造predicate,这样,我

Linq to sql 实现多条件的动态查询(方法一)

/// <summary> /// Linq to sql 多字段动态查询 /// </summary> /// <returns></returns> private List<TVacant> ViewBinding(ModelDataContext db,string fyno,string brd,string area,string city,string pos) { Expression<Func<TVacant, bo