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;
imported = importer.CreateNestedType (t, declaringType);
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);
}
}
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:
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 (importer.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;
imported = importer.CreateProperty (p, declaringType, get, set);
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 ());
}
cache.AddMemberImported (imported);
}
}
if (declaringType.IsInterface && declaringType.Interfaces != null) {
foreach (var iface in declaringType.Interfaces) {
cache.AddInterface (iface);
}
}
}