public ClrFieldProperty(PhpTypeInfo tinfo, FieldInfo field) : base(tinfo) { Field = field ?? throw new ArgumentNullException(nameof(field)); // _lazyGetter = new Lazy <Func <Context, object, PhpValue> >(() => (Func <Context, object, PhpValue>)CompileAccess(AccessMask.Read)); _lazyEnsureAlias = new Lazy <Func <Context, object, PhpAlias> >(() => (Func <Context, object, PhpAlias>)CompileAccess(AccessMask.ReadRef)); _lazyEnsureObject = new Lazy <Func <Context, object, object> >(() => (Func <Context, object, object>)CompileAccess(AccessMask.EnsureObject)); _lazyEnsureArray = new Lazy <Func <Context, object, IPhpArray> >(() => (Func <Context, object, IPhpArray>)CompileAccess(AccessMask.EnsureArray)); // SetValue(instance, PhpValue): void _lazySetValue = new Lazy <Action <Context, object, PhpValue> >(() => { if (IsReadOnly) { // error return((_, _instance, _value) => { PhpException.ErrorException(Resources.ErrResources.readonly_property_written, ContainingType.Name, PropertyName); }); } var pctx = Expression.Parameter(typeof(Context)); var pinstance = Expression.Parameter(typeof(object)); var pvalue = Expression.Parameter(typeof(PhpValue)); // field_expr: <instance>.<field> var field_expr = Bind(pctx, Expression.Convert(pinstance, Field.DeclaringType)); // expr: <field> := <value> // var expr = BinderHelpers.BindAccess(field_expr, pctx, AccessMask.Write, pvalue); // <-- does not allow passing PhpAlias Expression assign_expr = Expression.Block( Expression.Assign(field_expr, ConvertExpression.Bind(pvalue, Field.FieldType, pctx)), Expression.Empty()); // when assigning to PhpValue, we have to write by value or by ref if (Field.FieldType == typeof(PhpValue)) { // assign_expr: value.IsAlias ? (field_expr = value) : SetValue(ref field_expr, value) assign_expr = Expression.Condition( test: Expression.Property(pvalue, Cache.Properties.PhpValue_IsAlias), ifTrue: assign_expr, ifFalse: Expression.Call(Cache.Operators.SetValue_PhpValueRef_PhpValue, field_expr, pvalue) ); } // var lambda = Expression.Lambda(assign_expr, pctx, pinstance, pvalue); return((Action <Context, object, PhpValue>)lambda.Compile()); }); }
public ClrProperty(PhpTypeInfo tinfo, PropertyInfo property) : base(tinfo) { Debug.Assert(property != null); _property = property; _lazyGetter = new Lazy <Func <object, PhpValue> >(() => { var pinstance = Expression.Parameter(typeof(object)); var expr = Bind(null, Expression.Convert(pinstance, _property.DeclaringType)); expr = ConvertExpression.BindToValue(expr); // return((Func <object, PhpValue>)Expression.Lambda(expr, true, pinstance).Compile()); }); // SetValue(instance, PhpValue): void _lazySetValue = new Lazy <Action <Context, object, PhpValue> >(() => { if (IsReadOnly) { // error return(new Action <Context, object, PhpValue>((_, _instance, _value) => { PhpException.ErrorException(Resources.ErrResources.readonly_property_written, ContainingType.Name, PropertyName); })); } var pctx = Expression.Parameter(typeof(Context)); var pinstance = Expression.Parameter(typeof(object)); var pvalue = Expression.Parameter(typeof(PhpValue)); // expr: <instance>.<field> var expr = Bind(pctx, Expression.Convert(pinstance, _property.DeclaringType)); // expr: <property> := <value> expr = Expression.Assign(expr, ConvertExpression.Bind(pvalue, expr.Type, pctx)); // TODO: PHP semantic (Operators.SetValue) // {expr}: void var lambda = Expression.Lambda(Expression.Block(expr, Expression.Empty()), pctx, pinstance, pvalue); return((Action <Context, object, PhpValue>)lambda.Compile()); }); }