Einzelnen Beitrag anzeigen

Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#16

AW: Referenzen auf ungültige Objekte

  Alt 16. Mär 2011, 00:24
Ich weiß das

So sehen zwei Objekte von mir aus.
Die zu nutzenden Eigenschaften sind mit einem Attribut gekennzeichnet:

Delphi-Quellcode:
  TodPlayer = class(TodOlympicCustom)
  private
    FPerson: TodPerson;
    function get_StateType: TStateType;
    procedure set_StateType(const Value: TStateType);
  protected
    function get_Person: TodPerson; virtual;
    procedure set_Person(const Value: TodPerson); virtual; public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function GetClubName: String;
    [AttrOd]
    property Person: TodPerson read get_Person write set_Person; // EINE REFERENZ AUF EINE PERSON
    property StateType: TStateType read get_StateType write set_StateType;
  published
  end;

  TodMeleePlayer = class(TodPlayer)
  private
    FWin: Integer;
    FLose: Integer;
    FSetsP: Integer;
    FSetsC: Integer;
    FBallsP: Integer;
    FBallsC: Integer;
    FPlaced: Integer;
    ...
  public
    IsFree: Boolean;
    Pos: Integer;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    ...
    [AttrOd]
    property Win: Integer read get_Win write set_Win;
    [AttrOd]
    property Lose: Integer read get_Lose write set_Lose;
    [AttrOd]
    property SetsP: Integer read get_SetsP write set_SetsP;
    [AttrOd]
    property SetsC: Integer read get_SetsC write set_SetsC;
    [AttrOd]
    property BallsP: Integer read get_BallsP write set_BallsP;
    [AttrOd]
    property BallsC: Integer read get_BallsC write set_BallsC;
    [AttrOd]
    property Placed: Integer read get_Placed write set_Placed;
    ...
  published
  end;

Und hier mal ein paar Auszüge, wie ich die Referenz-Nilung erledige.
Ich hoffe, dass das einigermaßen durchschaubar ist.
Der Schwachpunkt ist derzeit sicher der Timer, macht aber praktisch keine Probleme.
Optimieren lässt sich da sicher noch einiges. Aber der Ansatz erscheint mir angenehmer als komplexe Observer-Patterns.


Delphi-Quellcode:
  odList: TObjectList<Tod>;

constructor Tod.Create(AOwner: TComponent);
begin
  inherited;
  odList.Add(Self); // od-Objekt registrieren

  odClass := ClassName; // Klassendefinitionen für meine RTTI-Funktionen und Datenspeicherung
  if Self is Todl then
    odClass := Copy(odClass, 4 + 1, MaxInt)
  else
    odClass := Copy(odClass, 3 + 1, MaxInt);
  odName := odClass;

  odId := GetNewOdId; // eindeutige ObjektID zuweisen
end;

destructor Tod.Destroy;
begin
  odList.Extract(Self); // Liste meiner od-Objekte
  odDestroy(Self);
  inherited;
end;

procedure odDestroy(od: Tod);
var
  I: Integer;
begin
  I := 0;
  while I <= odDataSetList.Count - 1 do // Liste von odControlern
  begin
    if odDataSetList[I].od = od then
      odDataSetList[I].od := nil;
    if odDataSetList[I].use_od = od then
      odDataSetList[I].CalcUse;
    Inc(I);
  end;
  TimerOdDestroy.Enabled := False; // im Anschluss gleich die Refrenzen nilen
  TimerOdDestroy.Enabled := True;
end;

procedure TTimerOdDestroy.DoTimer(Sender: TObject);
begin
  TimerOdDestroy.Enabled := False;
  odCheckPointer; // Referenzen nilen
end;

procedure odCheckPointer;
var
  iod: Tod;
begin
  for iod in odList do
  begin
    if (iod <> nil) and (not iod.HasNotOdPointer) then
    begin
      odProp.CheckPointer(iod); // Eigenschaften eines Objektes prüfen
    end;
  end;
end;

procedure TodProp.CheckPointer(const od: Tod);
var
  Context: TRttiContext;
  RttiType: TRttiType;
  PropInfo: TRttiProperty;
  F: Boolean;
  Attr: TCustomAttribute;
  Value: TValue;
  O: TObject;
  PropValue: String;
begin
  if not Assigned(od) then
    Exit;
  od.HasNotOdPointer := True;

  Context := TRttiContext.Create;
  RttiType := Context.GetType(od.ClassType);

  if Assigned(RttiType) then
  begin
    for PropInfo in RttiType.GetProperties do
    begin
      F := False;
      for Attr in PropInfo.GetAttributes do
      begin
        if Attr is AttrOd then
          F := True;
      end;
      if F then
      begin
        PropValue := '';
        Value := TValue.Empty;
        case PropInfo.PropertyType.TypeKind of
          tkClass:
            begin
              if PropInfo.IsWritable then // betrifft die Eigenschaft eine Objektreferenz?
              begin
                od.HasNotOdPointer := False;
                Value := PropInfo.GetValue(od);
                if (not Value.IsEmpty) then
                begin
                  O := Value.AsObject;
                  try // wenn das refenzierte Objekt nicht mehr existiert oder ein Zugriff fehl schlägt, dann nilen
                    if (O <> nil) and (O is Tod) and (not odExist(O as Tod)) then
                    begin
                      Value := nil;
                      PropInfo.SetValue(od, Value);
                    end;
                  except
                    Value := nil;
                    PropInfo.SetValue(od, Value);
                  end;
                end;
              end;
            end;
        end;
      end;
    end;
  end;

  Context.Free;
end;

function odExist(od: Tod): Boolean;
begin
  Result := odList.IndexOf(od) >= 0;
end;
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (16. Mär 2011 um 00:55 Uhr)
  Mit Zitat antworten Zitat