Как мне повторно вызвать исключение Delphi после его регистрации?

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

25
задан Rob Kennedy 27 May 2010 в 23:54
поделиться

6 ответов

Если вы хотите повторно вызвать исключение только при определенных условиях, напишите

procedure TForm3.Button1Click(Sender: TObject);
begin
  try
    raise Exception.Create('Bum');
  except
    on E: Exception do
    begin
      if MyHandleException(E) then
        raise;
    end;
  end;
end;

function TForm3.MyHandleException(AException: Exception): boolean;
begin
  ShowMessage(AException.Message);
  result := true/false;
end;
31
ответ дан 28 November 2019 в 20:38
поделиться

Исходя из поста Крейга Янга, я успешно использовал что-то вроде следующего кода. Вы можете сохранить исходное местоположение исключения, используя идентификатор «at» с функцией ExceptAddr. Исходный тип класса исключений и информация также сохраняются.

procedure MyHandleException(AMethod: string);
var
  e: Exception;
begin
  e := Exception(AcquireExceptionObject);
  e.Message := e.Message + ' raised in ' + AMethod; 
  raise e at ExceptAddr;
end;

try
  ...
except
  MyHandleException('MyMethod');
end;
9
ответ дан Wes 27 May 2010 в 23:54
поделиться

Вы можете попробовать использовать (system.pas):

function AcquireExceptionObject: Pointer;

AcquireExceptionObject возвращает указатель на текущий объект исключения и предотвращает освобождение объекта исключения при выходе из обработчика текущего исключения.

Примечание. AcquireExceptionObject увеличивает счетчик ссылок на объект исключения. Убедитесь, что счетчик ссылок уменьшается, когда объект исключения больше не нужен. Это происходит автоматически, если вы используете объект исключения для повторного вызова исключения. Во всех других случаях каждый вызов AcquireExceptionObject должен иметь соответствующий вызов ReleaseExceptionObject. Последовательности AcquireExceptionObject / ReleaseExceptionObject могут быть вложенными.

4
ответ дан André 27 May 2010 в 23:54
поделиться

Старая тема, но как насчет этого решения?

procedure MyHandleException(AException: Exception);
begin
  ShowMessage(AException.Message);
  AcquireExceptionObject;
  raise AException;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    raise Exception.Create('Bum');
  except
    on E: Exception do
      MyHandleException(E);
  end;
end;

Оно основано на первом коде, опубликованном Эдуардо.

1
ответ дан Roberto Schuster 27 May 2010 в 23:54
поделиться

Вы можете получить объект исключения перед вызовом вашего обработчика и оставить один обработчик самим обработчиком. Тем не менее, у вас по-прежнему много бремени «попробовать / исключить / сделать / закончить».

Procedure MyExceptionHandler(AException: Exception);
Begin
  Log(AException); // assuming it accepts an exception
  ShowMessage(AException.Message);
  raise AException; // the ref count will be leveled if you always raise it
End;

Procedure TForm3.Button1Click(Sender: TObject);
Begin
  Try
    Foo;
  Except On E:Exception Do
    MyExceptionHandler(Exception(AcquireExceptionObject));
  End;
End;

Однако, если вам нужно только избавиться от повторяющегося кода обработки ошибок в обработчиках событий, вы можете попробовать это:

Procedure TForm3.ShowException(AProc : TProc);
Begin
  Try
    AProc;
  Except On E:Exception Do Begin
    Log(E);
    ShowMessage(E.Message);
  End; End;
End;

Сокращение кода обработчика событий до этого:

Procedure TForm3.Button1Click(Sender: TObject);
Begin
  ShowException(Procedure Begin // anon method
    Foo; // if this call raises an exception, it will be handled by ShowException's handler
  End);
End;

Вы также можете заставить его работать для функций, используя параметризованные функции:

Function TForm3.ShowException<T>(AFunc : TFunc<T>) : T;
Begin
  Try
    Result := AFunc;
  Except On E:Exception Do Begin
    Log(E);
    ShowMessage(E.Message);
  End; End;
End;

И заставляя ShowException возвращать значение (выступая в качестве промежуточного):

Procedure TForm3.Button1Click(Sender: TObject);
Var
  V : Integer;
Begin
  V := ShowException<Integer>(Function : Integer Begin // anon method
    Result := Foo; // if this call raises an exception, it will be handled by ShowException's handler
  End);
End;

Или даже сделать так, чтобы процедура anon касалась непосредственно внешней переменной (ей) области действия:

Procedure TForm3.Button1Click(Sender: TObject);
Var
  V : Integer;
Begin
  ShowException(Procedure Begin // anon method
    V := Foo; // if this call raises an exception, it will be handled by ShowException's handler
  End);
End;

Существуют некоторые ограничения на взаимодействие переменных внутри тела анонимной функции и тех, которые определены в внешняя сфера, но для простых случаев, подобных этим, вам будет более чем хорошо.

0
ответ дан Eduardo 27 May 2010 в 23:54
поделиться

Вы должны иметь возможность просто использовать команду Raise , чтобы повторно вызвать исключение:

begin
  MyHandleException(E);
  Raise;
end;
2
ответ дан 28 November 2019 в 20:38
поделиться
Другие вопросы по тегам:

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