/// <summary> /// Creates a new ClrStaticTypeWrapper object. /// </summary> /// <param name="engine"> The associated script engine. </param> /// <param name="type"> The CLR type to wrap. </param> private ClrStaticTypeWrapper(ScriptEngine engine, Type type) : base(engine, GetPrototypeObject(engine, type)) { this.WrappedType = type; // Pick up the public constructors, if any. var constructors = type.GetConstructors(); if (constructors.Length > 0) { this.constructBinder = new ClrBinder(constructors); } else { // The built-in primitive types do not have constructors, but we still want to // allow their construction since there is no way to construct them otherwise. // Pretend that a constructor does exist. switch (Type.GetTypeCode(type)) { case TypeCode.Int32: this.constructBinder = new ClrBinder(ReflectionHelpers.Convert_ToInt32_Double); break; } } this.FastSetProperty("name", type.Name, PropertyAttributes.Configurable); if (this.constructBinder != null) { this.FastSetProperty("length", this.constructBinder.FunctionLength, PropertyAttributes.Configurable); } // Populate the fields, properties and methods. PopulateMembers(this, type, BindingFlags.Static); }
// 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); } }