Potrzebna pomoc przy zwalnianiu przy użyciu Free

0

Witam was mam taki oto fragment programu:

servicePort = interface(IInvokable)
['{40D5E173-70B7-E7E8-725D-FB4FAD6D69C3}']
Port : ServicePort;

Function TWebApi.LoginEnc(User,Password,Key : AnsiString): Boolean;
var
  _DoQuerySysStatusRequest : DoQuerySysStatusRequest;
  _DoQuerySysStatusResponse : doQuerySysStatusResponse;
begin
  Result := False;
  Password := EncodeString(GetStringHash(Password));
  Try
    _DoQuerySysStatusRequest := DoQuerySysStatusRequest.Create;
    _DoQuerySysStatusRequest.sysvar := 1;
    _DoQuerySysStatusRequest.countryId := 1;
    _DoQuerySysStatusRequest.webapiKey := Key;
    _doQuerySysStatusResponse := Port.doQuerySysStatus(_DoQuerySysStatusRequest);
    Result := True;
  Finally
    _DoQuerySysStatusRequest.Free;
    _doQuerySysStatusResponse.Free;
  End;
end;

I teraz jak wystąpi jaki kolwiek błąd w

Port.doQuerySysStatus(_DoQuerySysStatusRequest);

to _doQuerySysStatusResponse.Free;

 wywali błąd bo prubuje zwolnić coś czego nie ma. Jaki jest właściwy sposób rozwiązywania takich problemów?

Do głowy mi przychodzi najprostszy ale nieelegancki:

```delphi
Finally
    _DoQuerySysStatusRequest.Free;
    if Result Then _doQuerySysStatusResponse.Free;
End;

Drugi:

Finally
    _DoQuerySysStatusRequest.Free;
    if Assigned(_doQuerySysStatusResponse) Then _doQuerySysStatusResponse.Free;
End;

lub

Finally
    _DoQuerySysStatusRequest.Free;
    if _doQuerySysStatusResponse <> nil Then _doQuerySysStatusResponse.Free;
End;

Jak to powinno być fachowo i właściwie ?

2

Dam małą podpowiedź: Free nie zwolni obiektu, jeżeli wskazuje on na nil. Nasuwa Ci to jakąś myśl? Być może coś z zerowaniem zmiennych na początku procedury na przykład... :P

0

Czyli proponujesz takie rozwiązanie?

servicePort = interface(IInvokable)
['{40D5E173-70B7-E7E8-725D-FB4FAD6D69C3}']
Port : ServicePort;
 
Function TWebApi.LoginEnc(User,Password,Key : AnsiString): Boolean;
var
  _DoQuerySysStatusRequest : DoQuerySysStatusRequest;
  _DoQuerySysStatusResponse : doQuerySysStatusResponse;
begin
  Result := False;
  Password := EncodeString(GetStringHash(Password));
  Try
    _DoQuerySysStatusRequest := DoQuerySysStatusRequest.Create;
    _DoQuerySysStatusRequest.sysvar := 1;
    _DoQuerySysStatusRequest.countryId := 1;
    _DoQuerySysStatusRequest.webapiKey := Key;
    _doQuerySysStatusResponse := nil;
    _doQuerySysStatusResponse := Port.doQuerySysStatus(_DoQuerySysStatusRequest);
    Result := True;
  Finally
    _DoQuerySysStatusRequest.Free;
    _doQuerySysStatusResponse.Free;
  End;
end;
1

A teraz przyjmijmy, że tutaj: _DoQuerySysStatusRequest := DoQuerySysStatusRequest.Create; rzucony zostaje wyjątek i przeskakujemy do Finally. Na co wskazuje doQuerySysStatusResponse?
Btw, logiczniejsze byłyby już nazwy zmiennych Request i Response, bez tego całego _DoQuerySysStatus :P

2
function TWebApi.LoginEnc(User,Password,Key:AnsiString):Boolean;
var Request : DoQuerySysStatusRequest;
var Response : doQuerySysStatusResponse;
begin
  Result := False;
  Password := EncodeString(GetStringHash(Password));
  Request := DoQuerySysStatusRequest.Create;
  Request.sysvar := 1;
  Request.countryId := 1;
  Request.webapiKey := Key;
  try
    Result := True;
    Response := Port.doQuerySysStatus(Request);
    try
       ...
    finally
      Response.Free;
    end;
  finally
    Request.Free;
  end;
end;
0

Dziękuje wam za odpowiedzi i podpowiedzi. Dla pewności w przypadku bardziej złożonych procedur z większą ilością klas należy to zrobić np tak:

Function TWebApi.LoginEnc(User, Password, Key: Ansistring): Boolean;
var
  StatusRequest: DoQuerySysStatusRequest;
  StatusResponse: doQuerySysStatusResponse;
  LoginRequest: doLoginEncRequest;
  LoginResponse: doLoginEncResponse;
begin
  Result := False;
  Password := EncodeString(GetStringHash(Password));
  StatusRequest := DoQuerySysStatusRequest.Create;
  StatusRequest.sysvar := 1;
  StatusRequest.countryId := 1;
  StatusRequest.webapiKey := Key;
  Try
    StatusResponse := Port.doQuerySysStatus(StatusRequest);
    Try
      LoginRequest := doLoginEncRequest.Create;
      LoginRequest.userLogin := User;
      LoginRequest.userHashPassword := Password;
      LoginRequest.countryCode := 1;
      LoginRequest.webapiKey := Key;
      LoginRequest.localVersion := StatusResponse.verKey;
      LoginResponse := Port.doLoginEnc(LoginRequest);
      Try
        vSessionHandle := LoginResponse.sessionHandlePart;
        Result := True;
      Finally
        LoginResponse.Free;
      End;
    Finally
      StatusResponse.Free;
      LoginRequest.Free;
    End;
  Finally
    StatusRequest.Free;
  End;
end;
 

Lub upraszczając to tak:

Function TWebApi.LoginEnc(User, Password, Key: Ansistring): Boolean;
var
  StatusRequest: DoQuerySysStatusRequest;
  StatusResponse: doQuerySysStatusResponse;
  LoginRequest: doLoginEncRequest;
begin
  Result := False;
  Password := EncodeString(GetStringHash(Password));
  StatusRequest := DoQuerySysStatusRequest.Create;
  StatusRequest.sysvar := 1;
  StatusRequest.countryId := 1;
  StatusRequest.webapiKey := Key;
  Try
    StatusResponse := Port.doQuerySysStatus(StatusRequest);
    Try
      LoginRequest := doLoginEncRequest.Create;
      LoginRequest.userLogin := User;
      LoginRequest.userHashPassword := Password;
      LoginRequest.countryCode := 1;
      LoginRequest.webapiKey := Key;
      LoginRequest.localVersion := StatusResponse.verKey;
      vSessionHandle := Port.doLoginEnc(LoginRequest).sessionHandlePart;
    Finally
      StatusResponse.Free;
      LoginRequest.Free;
    End;
  Finally
    StatusRequest.Free;
  End;
end;
0

Znowu będzie problem jeżeli powstanie wyjątek w: LoginRequest := doLoginEncRequest.Create; czemu boisz się zagnieżdżać try?

0

Nie chcę zaśmiecać forum ale nie mogę znaleźć odpowiedzi nawet w artykule o wyjątkach czy idzie przechwytywać wyjątki w obrębie własnej klasy tzn. Powyższa procedura generuje jakiś wyjątek i chciałbym go przechwycić ale nie w bloku exception tylko w odrębnej procedurze tak jak się to robi np dla całej aplikacji:

Application.OnException := MyAppException; 

czyli

procedure TWebApi.MyAppException(Sender: TObject; E : Exception);
begin
  {Obsługa wyjątku}
  raise; //Przekazanie wyjątku dalej czyli w tym przypadku do aplikacji
end;
0
type TOnException=procedure(Sender: TObject; E : Exception)of Object;
...
private 
FOnException:TOnException;
...
property OnException:TOnException read FOnException write FOnException;

try
  ...
except 
  on E:Exception do if Assigned(FOnException) then FOnException(Self,E);
end;
0

Nie do końca mi o to chodziło bo teraz muszę zrobić tak:

var
  a: TWebApi;
begin
  a := TWebApi.Create;
  try
    a.OnException := JakaśProcedure;
    a.WykonajCos;
  finally
    a.Free;
  end;
end;

Czyli jak wystąpi wyjątek w WykonajCoś to zostanie wykonana JakaśProcedura.

A mi chodzi aby był kod w programie:

var
  a: TWebApi;
begin
  a := TWebApi.Create;
  try
    a.WykonajCos;
  finally
    a.Free;
  end;
end;

i teraz jak wystąpi wyjątek w WykonajCos to zamiast napisać tak:

TWebApi.WykonajCos;
begin
  Try
     strtoint('wyraz'); 
  Except
     ShowMessage('Cos sie stało');
     raise;
  End;
end;

To chciałbym tak

TWebApi.WykonajCos;
begin
   strtoint('wyraz'); 
end;

procedure TWebApi.oException(E: Exception);
begin
   ShowMessage('Cos sie stało');
   raise;
end;

Pytanie czy tak się da?

0

Takie rzeczy tylko w Erze i właśnie dla tego jej już nie ma.

0

Tak na logikę - nie wystarczy, jak będziesz w konstruktorze TWebApi od razu przypisywał fOnException?
Btw, raise E; w oException.

1
function TWebApi.LoginEnc(const user, password, key: AnsiString): boolean;
var
  statusRequest: DoQuerySysStatusRequest;
  statusResponse: DoQuerySysStatusResponse;
  loginRequest: DoLoginEncRequest;
begin
  Result := False;
  statusRequest := DoQuerySysStatusRequest.Create;
  try
    statusRequest.sysvar := 1;
    statusRequest.countryId := 1;
    statusRequest.webapiKey := key;
    statusResponse := Port.doQuerySysStatus(statusRequest);
    try
      loginRequest := DoLoginEncRequest.Create;
      try
        loginRequest.userLogin := user;
        loginRequest.userHashPassword := EncodeString(GetStringHash(password));
        loginRequest.countryCode := 1;
        loginRequest.webapiKey := key;
        loginRequest.localVersion := statusResponse.verKey;
        vSessionHandle := Port.doLoginEnc(loginRequest).sessionHandlePart;
        Result := True;
      finally
        loginRequest.Free;
      end;
    finally
      statusResponse.Free;
    end;
  finally
    statusRequest.Free;
  end;
end;

1 użytkowników online, w tym zalogowanych: 0, gości: 1