static PropertyDescriptor[] GetPropertiesImpl(object self, Attribute[] attributes) { bool ok = true; foreach (var attr in attributes) { if (attr.GetType() != typeof(BrowsableAttribute)) { ok = false; break; } } if (!ok) { return(new PropertyDescriptor[0]); } RubyClass immediateClass = GetImmediateClass(self); RubyContext context = immediateClass.Context; const int readable = 0x01; const int writable = 0x02; var properties = new Dictionary <string, int>(); using (context.ClassHierarchyLocker()) { immediateClass.ForEachMember(true, RubyMethodAttributes.DefaultVisibility, delegate(string /*!*/ name, RubyModule /*!*/ module, RubyMemberInfo /*!*/ member) { ExpressionType operatorType; int flag = 0; if (member is RubyAttributeReaderInfo) { flag = readable; } else if (member is RubyAttributeWriterInfo) { flag = writable; } else if (name == "initialize" || RubyUtils.TryMapOperator(name, out operatorType) != 0) { // Special case; never a property } else { int arity = member.GetArity(); if (arity == 0) { flag = readable; } else if (arity == 1 && name.LastCharacter() == '=') { flag = writable; } } if (flag != 0) { if (flag == writable) { name = name.Substring(0, name.Length - 1); } int oldFlag; properties.TryGetValue(name, out oldFlag); properties[name] = oldFlag | flag; } }); } var result = new List <PropertyDescriptor>(properties.Count); foreach (var pair in properties) { if (pair.Value == (readable | writable)) { result.Add(new RubyPropertyDescriptor(context, pair.Key, self, immediateClass.GetUnderlyingSystemType())); } } return(result.ToArray()); }