Exemple #1
0
		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);
				}
			}
		}