コード例 #1
0
ファイル: Metatables.cs プロジェクト: yatagarasu25/NLua
        /*
         * Pushes the value of a member or a delegate to call it, depending on the type of
         * the member. Works with static or instance members.
         * Uses reflection to find members, and stores the reflected MemberInfo object in
         * a cache (indexed by the type of the object and the name of the member).
         */
        private int GetMember(LuaState luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType)
        {
            bool       implicitStatic = false;
            MemberInfo member         = null;
            object     cachedMember   = CheckMemberCache(memberCache, objType, methodName);

            //object cachedMember=null;

            if (cachedMember is LuaNativeFunction)
            {
                translator.PushFunction(luaState, (LuaNativeFunction)cachedMember);
                translator.Push(luaState, true);
                return(2);
            }
            else if (cachedMember != null)
            {
                member = (MemberInfo)cachedMember;
            }
            else
            {
                //CP: Removed NonPublic binding search
                var members = objType.GetMember(methodName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase /*| BindingFlags.NonPublic*/);

                if (members.Length > 0)
                {
                    member = members [0];
                }
                else
                {
                    // If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static
                    // lookups for fields/properties/events -kevinh
                    //CP: Removed NonPublic binding search and made case insensitive
                    members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase /*| BindingFlags.NonPublic*/);

                    if (members.Length > 0)
                    {
                        member         = members [0];
                        implicitStatic = true;
                    }
                }
            }

            if (member != null)
            {
                if (member.MemberType == MemberTypes.Field)
                {
                    var field = (FieldInfo)member;

                    if (cachedMember == null)
                    {
                        SetMemberCache(memberCache, objType, methodName, member);
                    }

                    try {
                        translator.Push(luaState, field.GetValue(obj));
                    } catch {
                        LuaLib.LuaPushNil(luaState);
                    }
                }
                else if (member.MemberType == MemberTypes.Property)
                {
                    var property = (PropertyInfo)member;
                    if (cachedMember == null)
                    {
                        SetMemberCache(memberCache, objType, methodName, member);
                    }

                    try {
                        object val = property.GetValue(obj, null);
                        translator.Push(luaState, val);
                    } catch (ArgumentException) {
                        // If we can't find the getter in our class, recurse up to the base class and see
                        // if they can help.
                        if (objType is Type && !(((Type)objType) == typeof(object)))
                        {
                            return(GetMember(luaState, ((Type)objType).BaseType, obj, methodName, bindingType));
                        }
                        else
                        {
                            LuaLib.LuaPushNil(luaState);
                        }
                    } catch (TargetInvocationException e) {                      // Convert this exception into a Lua error
                        ThrowError(luaState, e);
                        LuaLib.LuaPushNil(luaState);
                    }
                }
                else if (member.MemberType == MemberTypes.Event)
                {
                    var eventInfo = (EventInfo)member;
                    if (cachedMember == null)
                    {
                        SetMemberCache(memberCache, objType, methodName, member);
                    }

                    translator.Push(luaState, new RegisterEventHandler(translator.pendingEvents, obj, eventInfo));
                }
                else if (!implicitStatic)
                {
                    if (member.MemberType == MemberTypes.NestedType)
                    {
                        // kevinh - added support for finding nested types
                        // cache us
                        if (cachedMember == null)
                        {
                            SetMemberCache(memberCache, objType, methodName, member);
                        }

                        // Find the name of our class
                        string name    = member.Name;
                        var    dectype = member.DeclaringType;

                        // Build a new long name and try to find the type by name
                        string longname   = dectype.FullName + "+" + name;
                        var    nestedType = translator.FindType(longname);
                        translator.PushType(luaState, nestedType);
                    }
                    else
                    {
                        // Member type must be 'method'
                        var wrapper = new LuaNativeFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).invokeFunction);

                        if (cachedMember == null)
                        {
                            SetMemberCache(memberCache, objType, methodName, wrapper);
                        }

                        translator.PushFunction(luaState, wrapper);
                        translator.Push(luaState, true);
                        return(2);
                    }
                }
                else
                {
                    // If we reach this point we found a static method, but can't use it in this context because the user passed in an instance
                    translator.ThrowError(luaState, "can't pass instance to static method " + methodName);
                    LuaLib.LuaPushNil(luaState);
                }
            }
            else
            {
                // kevinh - we want to throw an exception because meerly returning 'nil' in this case
                // is not sufficient.  valid data members may return nil and therefore there must be some
                // way to know the member just doesn't exist.
                translator.ThrowError(luaState, "unknown member name " + methodName);
                LuaLib.LuaPushNil(luaState);
            }

            // push false because we are NOT returning a function (see luaIndexFunction)
            translator.Push(luaState, false);
            return(2);
        }