代码之家  ›  专栏  ›  技术社区  ›  sid_com

如何使非方法的继承自动加载工作?

  •  1
  • sid_com  · 技术社区  · 7 年前
    package My::Win32::Console;
    use warnings;
    use strict;
    use parent qw( Win32::Console );
    
    sub new {
        my($class, $param1, $param2) = @_;
        my $self = {};
        if (defined($param1)
        and ($param1 == constant("STD_INPUT_HANDLE",  0)
        or   $param1 == constant("STD_OUTPUT_HANDLE", 0)
        or   $param1 == constant("STD_ERROR_HANDLE",  0)))
        {
            $self->{'handle'} = _GetStdHandle($param1);
            # https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224:
            $self->{'handle_is_std'} = 1;
        }
        else {
            $param1 = constant("GENERIC_READ", 0)    | constant("GENERIC_WRITE", 0) unless $param1;
            $param2 = constant("FILE_SHARE_READ", 0) | constant("FILE_SHARE_WRITE", 0) unless $param2;
            $self->{'handle'} = _CreateConsoleScreenBuffer($param1, $param2,
                                                  constant("CONSOLE_TEXTMODE_BUFFER", 0));
        }
        bless $self, $class;
        return $self;
    }
    
    sub DESTROY {
        my($self) = @_;
        # https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224:
        #_CloseHandle($self->{'handle'});
        _CloseHandle($self->{'handle'}) unless $self->{'handle_is_std'};
    }
    
    1;
    __END__
    

    https://rt.cpan.org/Public/Bug/Display.html?id=33513#txn-577224 在本模块的帮助下,我得到以下错误消息:

    # Use of inherited AUTOLOAD for non-method My::Win32::Console::constant()
    # is no longer allowed at C:/Strawberry/perl/site/lib/My/Win32/Console.pm line 10.
    

    有办法让这一切顺利吗?

    2 回复  |  直到 7 年前
        1
  •  4
  •   sid_com    7 年前

    问题是,您正在调用许多Win32::控制台子,就像它们在My::Win32::控制台中一样。


    解决方案1:正确参考潜艇。

    • constant 具有 Win32::Console::constant .
    • _CreateConsoleScreenBuffer 具有 Win32::Console::_CreateConsoleScreenBuffer .
    • 替换的单个实例 _CloseHandle 具有 Win32::Console::_CloseHandle .

    添加以下内容:

    BEGIN {
       *My::Win32::Console::constant                   = \&Win32::Console::constant;
       *My::Win32::Console::_CreateConsoleScreenBuffer = \&Win32::Console::_CreateConsoleScreenBuffer;
       *My::Win32::Console::_CloseHandle               = \&Win32::Console::_CloseHandle;
    }
    

    也就是说,我认为继承在这里是不合适的(而且做得很差)。最好是猴子补丁。

    package Win32::Console::PatchForRT33513;
    
    use strict;
    use warnings;
    
    use Win32::Console qw( );
    
    {
        my $old_new = Win32::Console->can('new');
        my $new_new = sub {
            my ($class, $param1, $param2) = @_;
            my $self = $old_new->(@_);
            $self->{handle_is_std} = 1
                if defined($param1)
                   && (  $param1 == Win32::Console::constant("STD_INPUT_HANDLE",  0)
                      || $param1 == Win32::Console::constant("STD_OUTPUT_HANDLE", 0)
                      || $param1 == Win32::Console::constant("STD_ERROR_HANDLE",  0)
                      );
    
            return $self;
        };
    
        no warnings qw( redefine );
        *Win32::Console::new = $new_new;
    }
    
    {
        my $old_DESTROY = Win32::Console->can('DESTROY');
        my $new_DESTROY = sub {
            my ($self) = @_;
            Win32::Console::_CloseHandle($self->{handle}) if !$self->{handle_is_std};
        };
    
        no warnings qw( redefine );
        *Win32::Console::DESTROY = $new_DESTROY;
    }
    
    1;
    

    这样,继承自Win32::Console的模块不会中断,您仍然可以继续使用

    use Win32::Console qw( STD_OUTPUT_HANDLE );
    my $c = Win32::Console->new(STD_OUTPUT_HANDLE);
    

    只要您先执行以下操作:

    use Win32::Console::PatchForRT33513;
    
        2
  •  3
  •   mob    7 年前

    我不知道我能不能解释得比 perldiag (如果你 use diagnostics )

    这将是 Perl 5.28中的致命错误 作为方法(使用@ISA层次结构)查找,即使 要自动加载的子程序被称为普通函数(例如。 “Foo::bar()”,而不是方法(例如,“Foo->bar()”或“$obj->bar()”)。

    此错误将在以后通过使用仅用于 可能使用旧行为的代码。因此,作为过渡步骤,Perl 当非方法使用继承的时,当前会发出可选警告 “自动加载”s。

    非方法。旧代码的简单修复方法是:在使用 依赖于从基类继承非方法的“AUTOLOAD” 启动。

    在当前的代码中是“使用AutoLoader;@ISA=qw(AutoLoader);” “使用AutoLoader‘AUTOLOAD’;”。

    5.28条。

    如果你希望能够使用 AUTOLOAD

    *My::Win32::Console::AUTOLOAD = \&Win32::Console::AUTOLOAD