Mono.CSharp.Foreach.CollectionForeach.ResolveGetEnumerator C# (CSharp) Method

ResolveGetEnumerator() private method

private ResolveGetEnumerator ( ResolveContext rc ) : Mono.CSharp.MethodGroupExpr
rc ResolveContext
return Mono.CSharp.MethodGroupExpr
			MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
			{
				//
				// Option 1: Try to match by name GetEnumerator first
				//
				var mexpr = Expression.MemberLookup (rc, rc.CurrentType, expr.Type,
					"GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);		// TODO: What if CS0229 ?

				var mg = mexpr as MethodGroupExpr;
				if (mg != null) {
					mg.InstanceExpression = expr;
					Arguments args = new Arguments (0);
					mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);

					// For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
					if (ambiguous_getenumerator_name)
						mg = null;

					if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
						return mg;
					}
				}

				//
				// Option 2: Try to match using IEnumerable interfaces with preference of generic version
				//
				TypeSpec iface_candidate = null;
				var t = expr.Type;
				do {
					var ifaces = t.Interfaces;
					if (ifaces != null) {
						foreach (var iface in ifaces) {
							if (TypeManager.generic_ienumerable_type != null && iface.MemberDefinition == TypeManager.generic_ienumerable_type.MemberDefinition) {
								if (iface_candidate != null && iface_candidate != TypeManager.ienumerable_type) {
									rc.Report.SymbolRelatedToPreviousError (expr.Type);
									rc.Report.Error (1640, loc,
										"foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
										expr.Type.GetSignatureForError (), TypeManager.generic_ienumerable_type.GetSignatureForError ());

									return null;
								}

								iface_candidate = iface;
								continue;
							}

							if (iface == TypeManager.ienumerable_type && iface_candidate == null) {
								iface_candidate = iface;
							}
						}
					}

					if (t.IsGenericParameter)
						t = t.BaseType;
					else
						t = null;

				} while (t != null);

				if (iface_candidate == null) {
					rc.Report.Error (1579, loc,
						"foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
						expr.Type.GetSignatureForError (), "GetEnumerator");

					return null;
				}

				var method = TypeManager.GetPredefinedMethod (iface_candidate, 
					MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null), loc);

				if (method == null)
					return null;

				mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
				mg.InstanceExpression = expr;
				return mg;
			}