-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSafeComponentReference.pas
130 lines (108 loc) · 3.65 KB
/
SafeComponentReference.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
unit SafeComponentReference;
interface
uses
System.Classes,
Sprinkles.InterfacedComponent;
type
IComponentReference<T: TComponent> = interface
function GetTarget: T;
procedure SetTarget(const AValue: T);
property Target: T read GetTarget write SetTarget;
end;
TSmartReferenceProxy<T: TComponent> = class(TInterfacedComponent, IComponentReference<T>)
private
FTarget: T;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
function GetTarget: T;
procedure SetTarget(const AValue: T);
end;
TSafeComponentReference<T: TComponent> = record // only records support operator overloading
private
FReference: IComponentReference<T>; // TInterfacedComponent let us use ARC magic
function GetTarget: T;
procedure SetTarget(const ATarget: T);
function Equals(const AOther: TSafeComponentReference<T>): Boolean;
public
property Target: T read GetTarget write SetTarget;
public
constructor Create(const ATarget: T);
class operator Implicit(const value: TSafeComponentReference<T>): T;
class operator Implicit(const value: T): TSafeComponentReference<T>;
class operator Implicit(value: TSafeComponentReference<T>): Pointer;
class operator Implicit(value: TSafeComponentReference<T>): TObject;
class operator Explicit(const value: TSafeComponentReference<T>): T;
class operator Equal(const a, b: TSafeComponentReference<T>): Boolean;
class operator NotEqual(const a, b: TSafeComponentReference<T>): Boolean;
end;
implementation
uses
System.Generics.Defaults;
function TSmartReferenceProxy<T>.GetTarget: T;
begin
Result := FTarget;
end;
procedure TSmartReferenceProxy<T>.Notification(AComponent: TComponent; Operation: TOperation);
begin
if (Operation = TOperation.opRemove) and (AComponent = (FTarget as TComponent)) then
FTarget := nil;
inherited;
end;
procedure TSmartReferenceProxy<T>.SetTarget(const AValue: T);
begin
if FTarget <> AValue then
begin
if Assigned(FTarget) then
FTarget.RemoveFreeNotification(Self);
FTarget := AValue;
if Assigned(FTarget) then
FTarget.FreeNotification(Self);
end;
end;
constructor TSafeComponentReference<T>.Create(const ATarget: T);
begin
FReference := TSmartReferenceProxy<T>.Create(nil);
FReference.Target := ATarget;
end;
class operator TSafeComponentReference<T>.Equal(const a, b: TSafeComponentReference<T>): Boolean;
begin
Result := a.Equals(b);
end;
function TSafeComponentReference<T>.Equals(const AOther: TSafeComponentReference<T>): Boolean;
begin
Result := TEqualityComparer<T>.Default.Equals(Target, AOther.Target);
end;
class operator TSafeComponentReference<T>.Explicit(const value: TSafeComponentReference<T>): T;
begin
Result := value.Target;
end;
function TSafeComponentReference<T>.GetTarget: T;
begin
Result := FReference.Target;
end;
class operator TSafeComponentReference<T>.Implicit(const value: TSafeComponentReference<T>): T;
begin
Result := value.Target;
end;
class operator TSafeComponentReference<T>.Implicit(const value: T): TSafeComponentReference<T>;
begin
Result := TSafeComponentReference<T>.Create(value);
end;
class operator TSafeComponentReference<T>.Implicit(value: TSafeComponentReference<T>): Pointer;
begin
Result := Pointer(value.Target);
end;
class operator TSafeComponentReference<T>.Implicit(value: TSafeComponentReference<T>): TObject;
begin
Result := value.Target;
end;
class operator TSafeComponentReference<T>.NotEqual(const a, b: TSafeComponentReference<T>): Boolean;
begin
Result := not a.Equals(b);
end;
procedure TSafeComponentReference<T>.SetTarget(const ATarget: T);
begin
FReference.Target := ATarget;
end;
end.