public Expression <BindingDelegate> CompileToDelegate( CastedExpressionBindingProperty expression, DataContextStack dataContext) { var expr = BindingCompiler.ReplaceParameters(expression.Expression, dataContext); expr = new ExpressionNullPropagationVisitor(e => true).Visit(expr); expr = ExpressionUtils.ConvertToObject(expr); return(Expression.Lambda <BindingDelegate>(expr, BindingCompiler.ViewModelsParameter, BindingCompiler.CurrentControlParameter)); }
public override void VisitPropertyBinding(ResolvedPropertyBinding propertyBinding) { if (BindingCompiler != null) { // try to compile bindings to see errors try { BindingCompiler.PrecompileBinding(propertyBinding.Binding, "id123", propertyBinding.Property.PropertyType); } catch (Exception exception) { Result.Errors.Add(exception); } } base.VisitPropertyBinding(propertyBinding); }
public Expression <BindingUpdateDelegate> CompileToUpdateDelegate(ParsedExpressionBindingProperty binding, DataContextStack dataContext) { var valueParameter = Expression.Parameter(typeof(object), "value"); var expr = BindingCompiler.ReplaceParameters(binding.Expression, dataContext); // don't throw exception, it is annoying to debug. if (expr.NodeType != ExpressionType.Parameter && (expr.NodeType != ExpressionType.MemberAccess || (!expr.CastTo <MemberExpression>().Member.As <PropertyInfo>()?.CanWrite ?? false)) && expr.NodeType != ExpressionType.Index) { return(null); } var assignment = Expression.Assign(expr, Expression.Convert(valueParameter, expr.Type)); return(Expression.Lambda <BindingUpdateDelegate>(assignment, BindingCompiler.ViewModelsParameter, BindingCompiler.CurrentControlParameter, valueParameter)); }
public Expression <BindingUpdateDelegate> CompileToUpdateDelegate(ParsedExpressionBindingProperty binding, DataContextStack dataContext) { var valueParameter = Expression.Parameter(typeof(object), "value"); var body = BindingCompiler.ReplaceParameters(binding.Expression, dataContext); body = ExpressionHelper.UpdateMember(body, valueParameter); if (body == null) { return(null); } return(Expression.Lambda <BindingUpdateDelegate>( body, BindingCompiler.ViewModelsParameter, BindingCompiler.CurrentControlParameter, valueParameter)); }
public (Expression builder, ParameterExpression[] fields) CreateBuilder(DotvvmConfiguration configuration) { var dict = new Dictionary <object, Expression>(); var callStack = new HashSet <object>(); var locals = new List <ParameterExpression>(); var results = new List <ParameterExpression>(); var body = new List <Expression>(); var dedupCache = new Dictionary <Expression, ParameterExpression>(ExpressionComparer.Instance); //var presetObjects = new Dictionary<object, Expression>(); MapObject(configuration, DotvvmConfigurationParameter, dict); Expression serializeObject(object obj, Type expectedType) { if (obj == null) { return(Expression.Constant(null, expectedType)); } if (dict.TryGetValue(obj, out var rrrr)) { return(rrrr); } if (!callStack.Add(obj)) { throw new NotSupportedException($"Reference cycles are not supported."); } var objType = obj.GetType(); ParameterExpression ret(Expression e, bool thisobj = true) { if (dedupCache.TryGetValue(e, out var p)) { return(p); } p = Expression.Parameter(e.Type); body.Add(Expression.Assign(p, e)); if (thisobj) { dict.Add(obj, p); } locals.Add(p); dedupCache.Add(e, p); return(p); } try { if (KnownObjects.TryGetValue(obj, out var result)) { return(result); } else if (objType.IsPrimitive || obj is string || obj is MemberInfo) { return(Expression.Constant(obj, objType.GetPublicBaseType())); } else if (obj is System.Collections.IEnumerable collection) { var element = ReflectionUtils.GetEnumerableType(collection.GetType()); Expression expr = collection.OfType <object>() .Select(e => serializeObject(e, element)) .Apply(c => Expression.NewArrayInit(element, c)); if (!objType.IsArray) { var targetType = objType.Name == "ImmutableList`1" ? typeof(ImmutableList) : //objType.Name == "ImmutableDictionary" ? typeof(ImmutableDictionary) : typeof(ImmutableArray); expr = expr.Apply(c => Expression.Call(null, targetType .GetMethods(BindingFlags.Static | BindingFlags.Public) .First(m => (m.Name == "Create" || m.Name == "To" + targetType.Name) && m.GetParameters().FirstOrDefault()?.ParameterType.IsArray == true) .MakeGenericMethod(new[] { element }), c )); } return(Expression.Convert(ret(expr), expectedType)); } else if (obj is Expression expression) { return(ret(Expression.Quote(expression))); } else if (obj is Delegate deleg) { if (!translatedDelegates.TryGetValue(deleg, out var method)) { throw new NotSupportedException("Could not serialize delegate"); } var(sanitizedMethod, parameters) = UnallowedConstantRemover.ReplaceBadConstants(method); return(ret(ExpressionUtils.Replace(Expression.Lambda(sanitizedMethod, parameters.Select(l => l.Item1)), parameters.Select(p => serializeObject(p.Item2, p.Item1.Type)).ToArray()))); } else if (obj is IBinding binding) { var properties = BindingCompiler.GetMinimalCloneProperties(binding) .Select(p => serializeObject(p, p.GetType())) .Apply(p => Expression.NewArrayInit(typeof(object), p)); return(ret(Expression.New( binding.GetType().GetConstructor(new[] { typeof(BindingCompilationService), typeof(IEnumerable <object>) }), ret(BindingCompilationService, thisobj: false), properties ))); } else { var map = Map(objType.GetPublicBaseType()); var ctorArgs = map.CtorArguments.Select(p => serializeObject(Evaluate(p, obj), p.ReturnType)).ToArray(); var newObj = ExpressionUtils.Replace(map.Ctor, ctorArgs); if (!newObj.Type.IsValueType || map.Properties.Any()) { newObj = ret(newObj); } foreach (var prop in map.Properties) { body.Add(ExpressionUtils.Replace(prop.Setter, newObj, serializeObject(Evaluate(prop.Getter, obj), prop.Getter.ReturnType))); } return(newObj); } } finally { callStack.Remove(obj); } } foreach (var req in requiredObjects) { var expr = serializeObject(req.Key, req.GetType().GetPublicBaseType()); var field = Expression.Parameter(req.Key.GetType().GetPublicBaseType(), req.Value); body.Add(Expression.Assign(field, expr)); results.Add(field); } return(Expression.Block(locals, body), results.ToArray()); }