IronRuby.Builtins.RubyClass.TryGetClrMethod C# (CSharp) Method

TryGetClrMethod() private method

There are basically 4 cases: 1) CLR method of the given name is not defined in the specified type. Do nothing, the method will be found as we traverse the hierarhy towards the Kernel module. 2) Otherwise 1) There is no RubyMemberInfo of given name present in the (type..Kernel] ancestors. We need to search all types in (type..Object] for CLR method overloads. 2) There is a RubyMemberInfo in a class, say C, in (type..Kernel]. We need to get CLR methods from (type..C) in addition to the members in the type. 1) C.HidesInheritedOverloads == true All overloads of the method we look for are in [type..C). 2) C.HidesInheritedOverloads == false All overloads of the method we look for are in [type..C) and in the RubyMemberInfo.
Doesn't include explicitly implemented interface methods. Including them would allow to call them directly (obj.foo) if the overload resolution succeeds. However, the interface methods are probably implemented explicitly for a reason: 1) There is a conflict in signatures -> the overload resolution would probably fail. 2) The class was designed with an intention to not expose the implementations directly.
private TryGetClrMethod ( Type type, BindingFlags bindingFlags, bool specialNameOnly, string name, string clrNamePrefix, string clrName, string altClrName, IronRuby.Runtime.Calls.RubyMemberInfo &method ) : bool
type System.Type
bindingFlags BindingFlags
specialNameOnly bool
name string
clrNamePrefix string
clrName string
altClrName string
method IronRuby.Runtime.Calls.RubyMemberInfo
return bool
        private bool TryGetClrMethod(Type/*!*/ type, BindingFlags bindingFlags, bool specialNameOnly, 
            string/*!*/ name, string clrNamePrefix, string/*!*/ clrName, string altClrName, out RubyMemberInfo method) {
            Context.RequiresClassHierarchyLock();

            // declared only:
            List<OverloadInfo> initialMembers = new List<OverloadInfo>(GetDeclaredClrMethods(type, bindingFlags, clrNamePrefix, clrName, altClrName, specialNameOnly));
            if (initialMembers.Count == 0) {
                // case [1]
                //
                // Note: This failure might be cached (see CacheFailure) based on the type and name, 
                // therefore it must not depend on any other mutable state:
                method = null;
                return false;
            }

            // If all CLR inherited members are to be returned we are done.
            // (creates a detached info; used by Kernel#clr_member)
            if ((bindingFlags & BindingFlags.DeclaredOnly) == 0) {
                method = MakeGroup(initialMembers, initialMembers.Count, specialNameOnly, true);
                return true;
            }

            // inherited overloads:
            List<RubyClass> ancestors = new List<RubyClass>();
            RubyMemberInfo inheritedRubyMember = null;
            bool skipHidden = false;

            ForEachAncestor((module) => {
                if (module != this) {
                    if (module.TryGetDefinedMethod(name, ref skipHidden, out inheritedRubyMember) && !inheritedRubyMember.IsSuperForwarder) {
                        return true;
                    }

                    // Skip classes that have no tracker, e.g. Fixnum(tracker) <: Integer(null) <: Numeric(null) <: Object(tracker).
                    // Skip CLR modules, their methods are not callable => do not include them into a method group.
                    // Skip all classes once hidden sentinel is encountered (no CLR overloads are visible since then).
                    if (!skipHidden && module.TypeTracker != null && module.IsClass) {
                        ancestors.Add((RubyClass)module);
                    }
                }

                // continue:
                return false;
            });

            // (method clr name, parameter types) => (overload, owner)
            Dictionary<Key<string, ValueArray<Type>>, ClrOverloadInfo> allMethods = null;

            if (inheritedRubyMember != null) {
                // case [2.2.2]: add CLR methods from the Ruby member:
                var inheritedGroup = inheritedRubyMember as RubyOverloadGroupInfo;

                if (inheritedGroup != null) {
                    AddMethodsOverwriteExisting(ref allMethods, inheritedGroup.MethodBases, inheritedGroup.OverloadOwners, specialNameOnly);
                } else if (inheritedRubyMember.IsRemovable) {
                    // The groups created below won't contain overloads defined above (if there are any).
                    // If this method is removed we need to invalidate them.
                    inheritedRubyMember.InvalidateGroupsOnRemoval = true;
                }
            }

            // populate classes in (type..Kernel] or (type..C) with method groups:
            for (int i = ancestors.Count - 1; i >= 0; i--) {
                var declared = ancestors[i].GetDeclaredClrMethods(ancestors[i].TypeTracker.Type, bindingFlags, clrNamePrefix, clrName, altClrName, specialNameOnly);
                if (AddMethodsOverwriteExisting(ref allMethods, declared, null, specialNameOnly)) {
                    // There is no cached method that needs to be invalidated.
                    //
                    // Proof:
                    // Suppose the group being created here overridden an existing method that is cached in a dynamic site invoked on some target class.
                    // Then either the target class is above all ancestors[i] or below some. If it is above then the new group doesn't 
                    // invalidate validity of the site. If it is below then the method resolution for the cached method would create
                    // and store to method tables all method groups in between the target class and the owner of the cached method, including the 
                    // one that contain overloads of ancestors[i]. But no module below inheritedRubyMember contains a method group of the name 
                    // being currently resolved.
                    ancestors[i].AddMethodNoCacheInvalidation(name, ancestors[i].MakeGroup(allMethods.Values));
                }
            }

            if (allMethods != null) {
                // add members declared in self:
                AddMethodsOverwriteExisting(ref allMethods, initialMembers, null, specialNameOnly);

                // return the group, it will be stored in the method table by the caller:
                method = MakeGroup(allMethods.Values);
            } else {
                method = MakeGroup(initialMembers, initialMembers.Count, specialNameOnly, false);
            }

            return true;
        }