public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache) { // // Not interested in members of nested private types unless the importer needs them // if (declaringType.IsPrivate && importer.IgnorePrivateMembers) { cache = MemberCache.Empty; return; } var loading_type = (MetaType) provider; const BindingFlags all_members = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; const MethodAttributes explicit_impl = MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.Final; Dictionary<MethodBase, MethodSpec> possible_accessors = null; List<EventSpec> imported_events = null; EventSpec event_spec; MemberSpec imported; MethodInfo m; MemberInfo[] all; try { all = loading_type.GetMembers (all_members); } catch (Exception e) { throw new InternalErrorException (e, "Could not import type `{0}' from `{1}'", declaringType.GetSignatureForError (), declaringType.MemberDefinition.DeclaringAssembly.FullName); } if (cache == null) { cache = new MemberCache (all.Length); // // Do the types first as they can be referenced by the members before // they are found or inflated // foreach (var member in all) { if (member.MemberType != MemberTypes.NestedType) continue; var t = (MetaType) member; // Ignore compiler generated types, mostly lambda containers if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate && importer.IgnorePrivateMembers) continue; try { imported = importer.CreateNestedType (t, declaringType); } catch (Exception e) { throw new InternalErrorException (e, "Could not import nested type `{0}' from `{1}'", t.FullName, declaringType.MemberDefinition.DeclaringAssembly.FullName); } cache.AddMemberImported (imported); } foreach (var member in all) { if (member.MemberType != MemberTypes.NestedType) continue; var t = (MetaType) member; if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate && importer.IgnorePrivateMembers) continue; importer.ImportTypeBase (t); } } // // Load base interfaces first to minic behaviour of compiled members // if (declaringType.IsInterface && declaringType.Interfaces != null) { foreach (var iface in declaringType.Interfaces) { cache.AddInterface (iface); } } if (!onlyTypes) { // // The logic here requires methods to be returned first which seems to work for both Mono and .NET // foreach (var member in all) { switch (member.MemberType) { case MemberTypes.Constructor: if (declaringType.IsInterface) continue; goto case MemberTypes.Method; case MemberTypes.Method: MethodBase mb = (MethodBase) member; var attrs = mb.Attributes; if ((attrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) { if (importer.IgnorePrivateMembers) continue; // Ignore explicitly implemented members if ((attrs & explicit_impl) == explicit_impl) continue; // Ignore compiler generated methods if (MetadataImporter.HasAttribute (CustomAttributeData.GetCustomAttributes (mb), "CompilerGeneratedAttribute", MetadataImporter.CompilerServicesNamespace)) continue; } imported = importer.CreateMethod (mb, declaringType); if (imported.Kind == MemberKind.Method && !imported.IsGeneric) { if (possible_accessors == null) possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default); // There are no metadata rules for accessors, we have to consider any method as possible candidate possible_accessors.Add (mb, (MethodSpec) imported); } break; case MemberTypes.Property: if (possible_accessors == null) continue; var p = (PropertyInfo) member; // // Links possible accessors with property // MethodSpec get, set; m = p.GetGetMethod (true); if (m == null || !possible_accessors.TryGetValue (m, out get)) get = null; m = p.GetSetMethod (true); if (m == null || !possible_accessors.TryGetValue (m, out set)) set = null; // No accessors registered (e.g. explicit implementation) if (get == null && set == null) continue; try { imported = importer.CreateProperty (p, declaringType, get, set); } catch (Exception ex) { throw new InternalErrorException (ex, "Could not import property `{0}' inside `{1}'", p.Name, declaringType.GetSignatureForError ()); } if (imported == null) continue; break; case MemberTypes.Event: if (possible_accessors == null) continue; var e = (EventInfo) member; // // Links accessors with event // MethodSpec add, remove; m = e.GetAddMethod (true); if (m == null || !possible_accessors.TryGetValue (m, out add)) add = null; m = e.GetRemoveMethod (true); if (m == null || !possible_accessors.TryGetValue (m, out remove)) remove = null; // Both accessors are required if (add == null || remove == null) continue; event_spec = importer.CreateEvent (e, declaringType, add, remove); if (!importer.IgnorePrivateMembers) { if (imported_events == null) imported_events = new List<EventSpec> (); imported_events.Add (event_spec); } imported = event_spec; break; case MemberTypes.Field: var fi = (FieldInfo) member; imported = importer.CreateField (fi, declaringType); if (imported == null) continue; // // For dynamic binder event has to be fully restored to allow operations // within the type container to work correctly // if (imported_events != null) { // The backing event field should be private but it may not int i; for (i = 0; i < imported_events.Count; ++i) { var ev = imported_events[i]; if (ev.Name == fi.Name) { ev.BackingField = (FieldSpec) imported; imported_events.RemoveAt (i); i = -1; break; } } if (i < 0) continue; } break; case MemberTypes.NestedType: // Already in the cache from the first pass continue; default: throw new NotImplementedException (member.ToString ()); } if (imported.IsStatic && declaringType.IsInterface) continue; cache.AddMemberImported (imported); } } }