Re[3]: SafePointerToInterface
От: Danchik Украина  
Дата: 10.11.05 14:41
Оценка:
Здравствуйте, Karluha, Вы писали:

D>>Напрашивается вопрос: для чего была произведено приведение IUnknown в Pointer. Есть догадка — для того чтобы запихтуть эго в какую то структуру, которая поддерживает только указатели.


K>Необходимо это для организации взаимных ссылок между двумя экземплярами, например Parent-Child. Это возможно только через Pointer, особенно если экземпляры описаны в разных, ничего не знающих друг о друге Library. Это значит что и нотификаций быть никаких не может, т.к. я ссылаюсь на чужой экземпляр IUnknown и при этом не хочу его держать.


Тебе необходимо организовать механизм WeakReference.
Вот набросал за пару минут пример реализации такого взаимодействия (untested):

unit Unit1;

interface

uses
  Windows, SysUtils, Classes;

type

  TWeakReference = class;

  IParent = interface
  ['{1D408CF3-962A-4FAE-ABC4-1910F6F89205}']
    procedure AddWeakRefernce (aReference : TWeakReference);
    procedure RemoveWeakRefernce (aReference : TWeakReference);
  end;

  TAbstractParent = class(TInterfacedObject, IParent)
  private
    FReferences : TList;
  protected
    procedure AddWeakRefernce (aReference : TWeakReference);
    procedure CleanupWeakReferences;
    function NeedReferencesList: TList;
    procedure RemoveWeakRefernce (aReference : TWeakReference);
  public
    destructor Destroy; override;
  end;

  TWeakReference = class
  private
    FReference: IUnknown;
  protected
    function GetReference: IUnknown;
    procedure SetReference(Value: IUnknown);
  public
    constructor Create (aReference : IUnknown);
    destructor Destroy; override;
    property Reference: IUnknown read GetReference write SetReference;
  end;

  TAbstractChild = class
  private
    FParent : TWeakReference;
  protected
    function GetParent: IUnknown;
    procedure SetParent(Value: IUnknown);
  public
    constructor Create;
    destructor Destroy; override;
    property Parent: IUnknown read GetParent write SetParent;
  end;

implementation

//==================================================================================================
// class TWeakReference
//==================================================================================================

constructor TWeakReference.Create(aReference: IInterface);
begin
  inherited Create;
  Reference := aReference;
end;

destructor TWeakReference.Destroy;
begin
  Reference := nil;
  inherited;
end;

function TWeakReference.GetReference: IUnknown;
begin
  Result := FReference;
end;

procedure TWeakReference.SetReference(Value: IUnknown);
var
  aParent : IParent;
begin
  if FReference = Value then
    Exit;

  if Supports (FReference, IParent, aParent) then
    aParent.RemoveWeakRefernce(Self);

  if Supports (Value, IParent, aParent) then
    aParent.AddWeakRefernce(Self);

  Pointer (FReference) := Pointer (Value);
end;

//==================================================================================================
// class TAbstractParent
//==================================================================================================

destructor TAbstractParent.Destroy;
begin
  CleanupWeakReferences;
  inherited;
end;

procedure TAbstractParent.AddWeakRefernce(aReference: TWeakReference);
begin
  NeedReferencesList.Add (aReference);
end;

procedure TAbstractParent.CleanupWeakReferences;
var
  K: Integer;
begin
  if FReferences = nil then
    Exit;

  { In this place pefrormance can be increased }
  while (FReferences <> nil) and (FReferences.Count > 0) do
    TWeakReference (FReferences [FReferences.Count - 1]).Reference := nil;

  FreeAndNil (FReferences);
end;

function TAbstractParent.NeedReferencesList: TList;
begin
  if FReferences = nil then
    FReferences := TList.Create;
  Result := FReferences;
end;

procedure TAbstractParent.RemoveWeakRefernce(aReference: TWeakReference);
begin
  if FReferences = nil then
    Exit;

  FReferences.Remove(aReference);
  if FReferences.Count = 0 then
    FreeAndNil (FReferences);
end;

//==================================================================================================
// class TAbstractChild
//==================================================================================================

constructor TAbstractChild.Create;
begin
  FParent := TWeakReference.Create(nil);
end;

destructor TAbstractChild.Destroy;
begin
  FParent.Free;
  inherited;
end;

function TAbstractChild.GetParent: IUnknown;
begin
  Result := FParent.Reference;
end;

procedure TAbstractChild.SetParent(Value: IUnknown);
begin
  if Parent = Value then
    Exit;

  FParent.Reference := Value;
  { in this place you should add code that appends this object as a children to a Parent}
end;

end.

Удачи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.