Perl: $SIG {__ УМИРАЮТ __}, оценка {} и отслеживание стека

Я столкнулся с той же проблемой в моем приложении ASP.NET MVC 4.

То, как я это решил, было в DatabaseContext. Передавая имя строки подключения, которую я хотел использовать через базовый конструктор.

public class DatabaseContext : DbContext
{ 
    public DatabaseContext()
        : base("DefaultConnection") // <-- this is what i added.
    {
    }

    public DbSet<SomeModel> SomeModels { get; set; }
}
12
задан trendels 9 June 2009 в 17:48
поделиться

3 ответа

Это небезопасно полагаться на то, что в документации объявлено устаревшим. Поведение может (и, вероятно, изменится) в будущем выпуске. Опора на устаревшее поведение привязывает вас к той версии Perl, которую вы используете сегодня.

К сожалению, я не вижу способа обойти это, что соответствует вашим критериям. «Правильное» решение - изменить внутренние методы для вызова Carp :: confess вместо die и удалить собственный обработчик $ SIG {__ DIE __} .

use strict;
use warnings;
use Carp qw'confess';

outer();

sub outer { middle(@_) }

sub middle { eval { inner() }; die $@ if $@ }

sub inner { confess("OH NOES!") }
__END__
OH NOES! at c:\temp\foo.pl line 11
    main::inner() called at c:\temp\foo.pl line 9
    eval {...} called at c:\temp\foo.pl line 9
    main::middle() called at c:\temp\foo.pl line 7
    main::outer() called at c:\temp\foo.pl line 5

Поскольку вы все равно умираете, возможно, вам не нужно перехватывать вызов inner () . (В вашем примере этого нет, ваш фактический код может отличаться.)

В вашем примере вы пытаетесь вернуть данные через $ @. Вы не можете этого сделать. Вместо этого используйте

my $x = eval { inner(@_) };

. (Я предполагаю, что это просто ошибка упрощения кода, достаточная для того, чтобы опубликовать его здесь.)

8
ответ дан 2 December 2019 в 07:03
поделиться

ОБНОВЛЕНИЕ: Я изменил код, чтобы переопределить die глобально, чтобы также можно было перехватить исключения из других пакетов.

Имеет ли следующие действия делают то, что вы хотите?

#!/usr/bin/perl

use strict;
use warnings;

use Devel::StackTrace;

use ex::override GLOBAL_die => sub {
    local *__ANON__ = "custom_die";
    warn (
        'Error: ', @_, "\n",
        "Stack trace:\n",
        Devel::StackTrace->new(no_refs => 1)->as_string, "\n",
    );
    exit 1;
};

use M; # dummy module to functions dying in other modules

outer();

sub outer {
    middle( @_ );
    M::n(); # M::n dies
}

sub middle {
    eval { inner(@_) };
    if ( my $x = $@ ) { # caught exception
        if (ref $x eq 'ARRAY') {
            print "we can handle this ...";
        }
        else {
            die $x; # rethrow
        }
    }
}

sub inner { die "OH NOES!" }
10
ответ дан 2 December 2019 в 07:03
поделиться

Обратите внимание, что переопределение die будет перехватывать только фактические вызовы к die , not Ошибки Perl, такие как разыменование undef .

Я не думаю, что общий случай возможен; весь смысл eval состоит в том, чтобы поглотить ошибки. Вы МОЖЕТЕ быть в состоянии полагаться на устаревшее поведение именно по этой причине: на данный момент другого способа сделать это нет. Но я не могу найти какой-либо разумный способ получить трассировку стека в каждом случае, не нарушая код обработки ошибок, который уже существует, но далеко внизу стека.

4
ответ дан 2 December 2019 в 07:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: