/// <summary>
        /// Attempts to invoke a meta-method and returns the result.
        /// </summary>
        /// <param name="type">The type of operation.</param>
        /// <param name="other">The other value.</param>
        /// <returns>The result of the meta-method, or null if not found.</returns>
        internal static ILuaValue AttempMetamethod(BinaryOperationType type, ILuaValue self, ILuaValue other)
        {
            if (type == BinaryOperationType.And || type == BinaryOperationType.Or)
            {
                return(null);
            }

            // Search the first object.
            ILuaValue ret   = null;
            var       self2 = self as ILuaTable;

            if (self2 != null && self2.MetaTable != null)
            {
                var t = self2.MetaTable.GetItemRaw(LuaString._metamethods[type]);
                if (t != null)
                {
                    ret = t.Invoke(LuaNil.Nil, false, -1, new LuaMultiValue(self, other));
                }
                else if (type == BinaryOperationType.Lte || type == BinaryOperationType.Gt)
                {
                    t = self2.MetaTable.GetItemRaw(LuaString._metamethods[BinaryOperationType.Lt]);
                    if (t != null)
                    {
                        ret = t.Invoke(LuaNil.Nil, false, -1, new LuaMultiValue(other, self)).Not();
                    }
                }
            }

            // Search the second object.
            var other2 = other as ILuaTable;

            if (ret == null && other2 != null && other2.MetaTable != null)
            {
                var t = other2.MetaTable.GetItemRaw(LuaString._metamethods[type]);
                if (t != null)
                {
                    ret = t.Invoke(LuaNil.Nil, true, -1, new LuaMultiValue(self, other));
                }
                else if (type == BinaryOperationType.Lte || type == BinaryOperationType.Gt)
                {
                    t = other2.MetaTable.GetItemRaw(LuaString._metamethods[BinaryOperationType.Lt]);
                    if (t != null)
                    {
                        ret = t.Invoke(LuaNil.Nil, true, -1, new LuaMultiValue(other, self)).Not();
                    }
                }
            }

            // Fix the arguments for comparisons.
            if (ret != null)
            {
                ret = ret.Single();
                switch (type)
                {
                case BinaryOperationType.Gt:
                case BinaryOperationType.Gte:
                case BinaryOperationType.NotEquals:
                    ret = LuaBoolean.Create(!ret.IsTrue);
                    break;

                case BinaryOperationType.Equals:
                case BinaryOperationType.Lt:
                case BinaryOperationType.Lte:
                    ret = LuaBoolean.Create(ret.IsTrue);
                    break;
                }
            }

            return(ret);
        }