public DefineProperty ( object key, |
||
key | object | The property key of the property to modify. |
descriptor | The property value and attributes. | |
throwOnError | bool | |
return | bool |
/// <summary> /// Defines or redefines the value and attributes of a property. The prototype chain is /// not searched so if the property exists but only in the prototype chain a new property /// will be created. /// </summary> /// <param name="key"> The property key of the property to modify. </param> /// <param name="descriptor"> The property value and attributes. </param> /// <param name="throwOnError"> <c>true</c> to throw an exception if the property could not /// be set. This can happen if the property is not configurable or the object is sealed. </param> /// <returns> <c>true</c> if the property was successfully modified; <c>false</c> otherwise. </returns> public override bool DefineProperty(object key, PropertyDescriptor descriptor, bool throwOnError) { // Check for revocation. if (target == null || handler == null) { throw new JavaScriptException(ErrorType.TypeError, "Cannot call 'defineProperty' on a proxy that has been revoked."); } // Call the handler, if one exists. var trap = handler.GetMethod("defineProperty"); if (trap == null) { return(target.DefineProperty(key, descriptor, throwOnError)); } var result = TypeConverter.ToBoolean(trap.CallLateBound(handler, target, key, descriptor.ToObject(Engine))); // Validate. if (!result) { if (throwOnError) { throw new JavaScriptException(ErrorType.TypeError, $"'defineProperty' on proxy: trap returned falsish for property '{TypeConverter.ToString(key)}'."); } return(false); } var targetDescriptor = target.GetOwnPropertyDescriptor(key); if (targetDescriptor.Exists) { if (!IsCompatiblePropertyDescriptor(target.IsExtensible, descriptor, targetDescriptor)) { throw new JavaScriptException(ErrorType.TypeError, $"'defineProperty' on proxy: trap returned truish for adding property '{TypeConverter.ToString(key)}' that is incompatible with the existing property in the proxy target."); } if (descriptor.Exists && !descriptor.IsConfigurable && targetDescriptor.IsConfigurable) { throw new JavaScriptException(ErrorType.TypeError, $"'defineProperty' on proxy: trap returned truish for defining non-configurable property '{TypeConverter.ToString(key)}' which is either non-existent or configurable in the proxy target."); } if (!targetDescriptor.IsAccessor && !targetDescriptor.IsConfigurable && targetDescriptor.IsWritable) { if (descriptor.Exists && !descriptor.IsWritable) { throw new JavaScriptException(ErrorType.TypeError, $"'defineProperty' on proxy: trap returned truish for defining non-configurable property '{TypeConverter.ToString(key)}' which cannot be non-writable, unless there exists a corresponding non-configurable, non-writable own property of the target object."); } } } else { if (!target.IsExtensible) { throw new JavaScriptException(ErrorType.TypeError, $"'defineProperty' on proxy: trap returned truish for adding property '{TypeConverter.ToString(key)}' to the non-extensible proxy target."); } if (descriptor.Exists && !descriptor.IsConfigurable) { throw new JavaScriptException(ErrorType.TypeError, $"'defineProperty' on proxy: trap returned truish for defining non-configurable property '{TypeConverter.ToString(key)}' which is either non-existent or configurable in the proxy target."); } } return(true); }
public static ObjectInstance DefineProperty([JSParameter(JSParameterFlags.DoNotConvert)] ObjectInstance obj, string propertyName, [JSParameter(JSParameterFlags.DoNotConvert)] ObjectInstance attributes) { var defaults = obj.GetOwnPropertyDescriptor(propertyName); var descriptor = PropertyDescriptor.FromObject(attributes, defaults); obj.DefineProperty(propertyName, descriptor, true); return(obj); }
public static bool DefineProperty(ObjectInstance target, object propertyKey, object attributes) { propertyKey = TypeConverter.ToPropertyKey(propertyKey); var defaults = target.GetOwnPropertyDescriptor(propertyKey); if (!(attributes is ObjectInstance)) { throw new JavaScriptException(ErrorType.TypeError, $"Invalid property descriptor '{attributes}'."); } var descriptor = PropertyDescriptor.FromObject((ObjectInstance)attributes, defaults); return(target.DefineProperty(propertyKey, descriptor, throwOnError: false)); }
public static ObjectInstance DefineProperty(ObjectInstance obj, object key, object attributes) { key = TypeConverter.ToPropertyKey(key); var defaults = obj.GetOwnPropertyDescriptor(key); if (!(attributes is ObjectInstance)) { throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Invalid descriptor for property '{propertyName}'."); } var descriptor = PropertyDescriptor.FromObject((ObjectInstance)attributes, defaults); obj.DefineProperty(key, descriptor, true); return(obj); }
// METHODS //_________________________________________________________________________________________ /// <summary> /// Populates the given object with properties, field and methods based on the given .NET /// type. /// </summary> /// <param name="target"> The object to populate. </param> /// <param name="type"> The .NET type to search for methods. </param> /// <param name="flags"> <c>BindingFlags.Static</c> to populate static methods; /// <c>BindingFlags.Instance</c> to populate instance methods. </param> internal static void PopulateMembers(ObjectInstance target, Type type, BindingFlags flags) { // Register static methods as functions. var methodGroups = new Dictionary <string, List <MethodBase> >(); foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | flags)) { switch (member.MemberType) { case MemberTypes.Method: MethodInfo method = (MethodInfo)member; List <MethodBase> methodGroup; if (methodGroups.TryGetValue(method.Name, out methodGroup) == true) { methodGroup.Add(method); } else { methodGroups.Add(method.Name, new List <MethodBase>() { method }); } break; case MemberTypes.Property: PropertyInfo property = (PropertyInfo)member; var getMethod = property.GetGetMethod(); ClrFunction getter = getMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(getMethod)); var setMethod = property.GetSetMethod(); ClrFunction setter = setMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(setMethod)); target.DefineProperty(property.Name, new PropertyDescriptor(getter, setter, PropertyAttributes.NonEnumerable), false); // Property getters and setters also show up as methods, so remove them here. // NOTE: only works if properties are enumerated after methods. if (getMethod != null) { methodGroups.Remove(getMethod.Name); } if (setMethod != null) { methodGroups.Remove(setMethod.Name); } break; case MemberTypes.Field: FieldInfo field = (FieldInfo)member; ClrFunction fieldGetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldGetterBinder(field)); ClrFunction fieldSetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldSetterBinder(field)); target.DefineProperty(field.Name, new PropertyDescriptor(fieldGetter, fieldSetter, PropertyAttributes.NonEnumerable), false); break; case MemberTypes.Constructor: case MemberTypes.NestedType: case MemberTypes.Event: case MemberTypes.TypeInfo: // Support not yet implemented. break; } } foreach (var methodGroup in methodGroups.Values) { var binder = new ClrBinder(methodGroup); var function = new ClrFunction(target.Engine.Function.InstancePrototype, binder); target.FastSetProperty(binder.Name, function, PropertyAttributes.NonEnumerable, overwriteAttributes: true); } }
// METHODS //_________________________________________________________________________________________ /// <summary> /// Populates the given object with properties, field and methods based on the given .NET /// type. /// </summary> /// <param name="target"> The object to populate. </param> /// <param name="type"> The .NET type to search for methods. </param> /// <param name="flags"> <c>BindingFlags.Static</c> to populate static methods; /// <c>BindingFlags.Instance</c> to populate instance methods. </param> internal static void PopulateMembers(ObjectInstance target, Type type, BindingFlags flags) { // Register static methods as functions. var methodGroups = new Dictionary<string, List<MethodBase>>(); foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | flags)) { switch (member.MemberType) { case MemberTypes.Method: MethodInfo method = (MethodInfo)member; List<MethodBase> methodGroup; if (methodGroups.TryGetValue(method.Name, out methodGroup) == true) methodGroup.Add(method); else methodGroups.Add(method.Name, new List<MethodBase>() { method }); break; case MemberTypes.Property: PropertyInfo property = (PropertyInfo)member; var getMethod = property.GetGetMethod(); ClrFunction getter = getMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(getMethod)); var setMethod = property.GetSetMethod(); ClrFunction setter = setMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(setMethod)); target.DefineProperty(property.Name, new PropertyDescriptor(getter, setter, PropertyAttributes.NonEnumerable), false); // Property getters and setters also show up as methods, so remove them here. // NOTE: only works if properties are enumerated after methods. if (getMethod != null) methodGroups.Remove(getMethod.Name); if (setMethod != null) methodGroups.Remove(setMethod.Name); break; case MemberTypes.Field: FieldInfo field = (FieldInfo)member; ClrFunction fieldGetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldGetterBinder(field)); ClrFunction fieldSetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldSetterBinder(field)); target.DefineProperty(field.Name, new PropertyDescriptor(fieldGetter, fieldSetter, PropertyAttributes.NonEnumerable), false); break; case MemberTypes.Constructor: case MemberTypes.NestedType: case MemberTypes.Event: case MemberTypes.TypeInfo: // Support not yet implemented. break; } } foreach (var methodGroup in methodGroups.Values) { var binder = new ClrBinder(methodGroup); var function = new ClrFunction(target.Engine.Function.InstancePrototype, binder); target.FastSetProperty(binder.Name, function, PropertyAttributes.NonEnumerable, overwriteAttributes: true); } }
public static ObjectInstance DefineProperty(ObjectInstance obj, object key, object attributes) { key = TypeConverter.ToPropertyKey(key); var defaults = obj.GetOwnPropertyDescriptor(key); if (!(attributes is ObjectInstance)) throw new JavaScriptException(obj.Engine, ErrorType.TypeError, "Invalid descriptor for property '{propertyName}'."); var descriptor = PropertyDescriptor.FromObject((ObjectInstance)attributes, defaults); obj.DefineProperty(key, descriptor, true); return obj; }
// CODE GEN METHODS //_________________________________________________________________________________________ /// <summary> /// Sets the value of a object literal property to a value. /// </summary> /// <param name="obj"> The object to set the property on. </param> /// <param name="key"> The property key (can be a string or a symbol). </param> /// <param name="value"> The value to set. </param> public static void SetObjectLiteralValue(ObjectInstance obj, object key, object value) { obj.DefineProperty(key, new PropertyDescriptor(value, Library.PropertyAttributes.FullAccess), throwOnError: false); }
/// <summary> /// Sets the value of a object literal property to a setter. If the value already has a /// getter then it will be retained. /// </summary> /// <param name="obj"> The object to set the property on. </param> /// <param name="key"> The property key (can be a string or a symbol).</param> /// <param name="setter"> The setter function. </param> public static void SetObjectLiteralSetter(ObjectInstance obj, object key, UserDefinedFunction setter) { var descriptor = obj.GetOwnPropertyDescriptor(key); if (descriptor.Exists == false || !descriptor.IsAccessor) obj.DefineProperty(key, new PropertyDescriptor(null, setter, Library.PropertyAttributes.FullAccess), throwOnError: false); else obj.DefineProperty(key, new PropertyDescriptor(descriptor.Getter, setter, Library.PropertyAttributes.FullAccess), throwOnError: false); }