How to define a default indexed property for a TObject class in Delphi
Given these classes;
type TMyItem = class(TObject)
private
FReference: String;
FOtherProperty: TObject;
public
property Reference: String read FReference write FReference;
property OtherProperty: String read FOtherPropertywrite FOtherProperty;
end;
type TMyListClass = class(TObjectList<TMyItem>)
public
function IndexOf(const AReference: String): Integer; overload;
end;
function TMyListClass.IndexOf(const AReference: String): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to Count - 1 do
if Items[I].Reference = AReference then
begin
Result := I;
break;
end;
end;
type TMyClass = class(TObject)
private
FList: TObjectList<TOtherClass>;
public
property List: TObjectList<TOtherClass> read FList write FList;
end;
How do I implement a property/function/enumerator on TMyClass so that instead of this
AMyClass.List.Items[AMyClass.List.IndexOf(ARef)].OtherProperty := AOtherObject;
开发者_开发百科
I can do this
AMyClass[ARef].OtherProperty := AOtherObject;
I thought it would be a matter of making a default property, but you can't pass a parameter to a property like you would a function.
EDIT 07/12.
OK. So if I make List
the default;
, I believe this would work.
AMyClass[AMyClass.IndexOf(ARef)].OtherProperty := AOtherObject;
The default
keyword usage you are thinking of only works on array properties, but your List
property is not an array property.
To get the kind of syntax you originally asked for:
AMyClass[ARef].OtherProperty := ...;
You will have to do the following:
type
TMyClass = class(TObject)
private
FList: TObjectList<TMyItem>;
function GetItem(const AReference: String): TMyItem;
procedure SetItem(const AReference: String; AItem: TMyItem);
public
property List: TObjectList<TMyItem> read FList;
property Item[const AReference: String]: TMyItem read GetItem write SetItem; default;
end;
...
function TMyClass.GetItem(const AReference: String): TMyItem;
var
Index: Integer;
begin
Index := FList.IndexOf(AReference);
if Index = -1 then
raise EArgumentException.Create('Reference not found');
Result := FList[Index];
end;
procedure TMyClass.SetItem(const AReference: String; AItem: TMyItem);
var
Index: Integer;
begin
Index := FList.IndexOf(AReference);
if Index = -1 then
FList.Add(AItem)
else
FList[Index] := AItem;
end;
Edit. Sorry, I didn't update the page before posting, therefore my answer is pretty much the same as the one of @RemyLebeau.
I'm not sure I understand you right, but you can do something like this
type TMyClass = class(TObject)
private
FList: TMyListClass;
function GetOtherProperty(const ARef: String): TObject;
procedure SetOtherProperty(const ARef: String; AValue: TObject);
public
property List: TMyListClass read FList write FList;
property OtherProperty[const ARef: String]: TObject read GetOtherProperty write SetOtherProperty;
end;
...
function TMyClass.GetOtherProperty(const ARef: String): TObject;
begin
Result := ... ;// find item
if ( Result <> nil ) then
Result := Result.OtherProperty;
end;
procedure TMyClass.SetOtherProperty(const ARef: String; AValue: TObject);
var item: TMyItem;
begin
item := ... ;// find item
if ( item <> nil ) then
item.OtherProperty := AValue;
end;
If TMyItem.FReference
is unique, you may also implement something like TDictionary<String, TMyItem>
in your TMyListClass
and return TMyItem
directly instead of its index
TMyListClass = class(TObjectList<TMyItem>)
private
FItemDic: TDictionary<String, TMyItem>;
function GetMyItem(const ARef: String): TMyItem;
protected
procedure Notify(constref AValue: TMyItem; ACollectionNotification: TCollectionNotification); override;
public
property ItemsByRef[const ARef: String]: TMyItem read GetMyItem;
constructor Create();
destructor Destroy(); override;
end;
...
procedure TMyListClass.Notify(constref AValue: TMyItem; ACollectionNotification: TCollectionNotification);
begin
inherited Notify(AValue, ACollectionNotification);
if ( FItemDic = nil ) then Exit;
case ( ACollectionNotification ) of
cnAdded : FItemDic.AddOrSetValue( AValue.Reference, AValue );
cnRemoved, cnExtracted: FItemDic.Remove( AValue.Reference );
end;
end;
function TMyListClass.GetMyItem(const ARef: String): TMyItem;
begin
FItemDic.TryGetValue( ARef, Result );
end;
constructor TMyListClass.Create();
begin
inherited;
FItemDic := TDictionary<String, TMyItem>.Create();
end;
destructor TMyListClass.Destroy();
begin
FreeAndNil(FItemDic);
inherited Destroy();
end;
The code above was written in Lazarus 2.2.2, but it should work in latest Delphi as well.
精彩评论