protected override Expression VisitConstant(ConstantExpression node) { int field; Expression result = parsedLambda.ParsedConstants.TryGetValue(node, out field) ? constantsBuilder.MakeAccess(parsedLambda.ConstantsParameter, field) : base.VisitConstant(node); if (node.Value is Expression) { if (parsedLambda.ClosureParameter != null) { var exp = (Expression)node.Value; var temp = new ClosureSubstituter(parsedLambda.ClosureParameter, closureBuilder, parsedLambda.ParsedParameters).Visit(exp); if (temp != exp) { var constructor = typeof(ExpressionQuoter).GetConstructor(new[] { typeof(object) }); result = Expression.Convert(Expression.Call(Expression.New(constructor, parsedLambda.ClosureParameter), typeof(ExpressionVisitor).GetMethod("Visit", new[] { typeof(Expression) }), new[] { result }), node.Type); } } } return(result); }
private Func <object> BuildConstants(Type type, ClosureSubstituter closureSubstituter) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(object), new[] { typeof(object[]) }, typeof(ExpressionClosureBuilder), true); var root = Expression.Parameter(type); var consts = new object[hashtable.Count]; using (var il = new GroboIL(method)) { il.Newobj(type.GetConstructor(Type.EmptyTypes)); // stack: [new Constants()] var result = il.DeclareLocal(type, "result"); il.Stloc(result); // result = new Constants(); stack: [] int index = 0; foreach (DictionaryEntry entry in hashtable) { var pair = (Tuple <Type, object>)entry.Key; var constType = pair.Item1; consts[index] = pair.Item2 is Expression?closureSubstituter.Visit((Expression)pair.Item2) : pair.Item2; var fieldAccessor = constantsBuilder.MakeAccess(root, ((int?)entry.Value).Value); var pathToField = new List <FieldInfo>(); while (fieldAccessor.NodeType != ExpressionType.Parameter) { var memberExpression = (MemberExpression)fieldAccessor; pathToField.Add((FieldInfo)memberExpression.Member); fieldAccessor = memberExpression.Expression; } pathToField.Reverse(); il.Ldloc(result); for (int i = 0; i < pathToField.Count - 1; ++i) { il.Ldflda(pathToField[i]); // stack: [ref result.field] il.Dup(); // stack: [ref result.field, ref result.field] var fieldType = pathToField[i].FieldType; il.Ldind(fieldType); // stack: [ref result.field, result.field] var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); // if(result.field != null) goto notNull; stack: [ref result.field] il.Dup(); // stack: [ref result.field, ref result.field] il.Newobj(fieldType.GetConstructor(Type.EmptyTypes)); // stack: [ref result.field, ref result.field, new field()] il.Stind(fieldType); // result.field = new field(); stack: [ref result.field] il.MarkLabel(notNullLabel); il.Ldind(fieldType); // stack: [result.field] } il.Ldarg(0); // stack: [path, args] il.Ldc_I4(index++); // stack: [path, args, index] il.Ldelem(typeof(object)); // stack: [path, args[index]] var field = pathToField.Last(); if (!constType.IsValueType) { il.Castclass(field.FieldType); // stack: [path, (FieldType)args[index]] } else { il.Unbox_Any(constType); if (field.FieldType != constType) { var constructor = field.FieldType.GetConstructor(new[] { constType }); if (constructor == null) { throw new InvalidOperationException(string.Format("Missing constructor of type '{0}' with parameter of type '{1}'", Formatter.Format(field.FieldType), Formatter.Format(constType))); } il.Newobj(constructor); } } il.Stfld(field); // path.field = (FieldType)args[index]; stack: [] } il.Ldloc(result); il.Ret(); } var func = (Func <object[], object>)method.CreateDelegate(typeof(Func <object[], object>)); return(() => func(consts)); }