我想做类似的事情,但它不会编译因为无法分配对。
var
MyDictionary: TDictionary<TGuid, TCustomRecord>;
Pair: TPair<TGuid, TCustomRecord>;
begin
// ... create and populate my dictionary ...
foreach Pair in MyDictionary do
begin
PairRef.Value.MyField := PairRef.Value.MyField + 1;
end;
end
为了清楚起见,我知道如何通过更多代码实现这一目标,我正在寻找简洁易读的内容。
答案 0 :(得分:8)
这是一个简单的程序,它显示了使用带有TDictionary
的记录和对象的不同处理。
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Generics.Collections;
type
TMyRecord = record
Field : Integer;
end;
TMyObject = class
Field : Integer;
end;
procedure UseObjectDict;
var
LDict : TDictionary<TGUID, TMyObject>;
LValue : TMyObject;
begin
write( 'TMyObject: ' );
LDict := TObjectDictionary<TGUID, TMyObject>.Create( [doOwnsValues] );
try
// populate
while LDict.Count < 10 do
begin
LDict.Add( TGuid.NewGuid, TMyObject.Create );
end;
// update
for LValue in LDict.Values do
begin
LValue.Field := LValue.Field + 1;
end;
// output
for LValue in LDict.Values do
begin
write( LValue.Field, ', ' );
end;
Writeln;
finally
LDict.Free;
end;
end;
procedure UseRecordDict;
var
LDict : TDictionary<TGUID, TMyRecord>;
LKey : TGUID;
LValue : TMyRecord;
begin
write( 'TMyRecord: ' );
LDict := TDictionary<TGUID, TMyRecord>.Create;
try
// populate
while LDict.Count < 10 do
begin
LValue.Field := 0;
LDict.Add( TGuid.NewGuid, LValue );
end;
// update
for LKey in LDict.Keys do
begin
LValue.Field := LDict[LKey].Field + 1;
LDict.AddOrSetValue( LKey, LValue );
end;
// output
for LValue in LDict.Values do
begin
write( LValue.Field, ', ' );
end;
Writeln;
finally
LDict.Free;
end;
end;
begin
ReportMemoryLeaksOnShutdown := True;
try
UseObjectDict;
UseRecordDict;
except
on E : Exception do
Writeln( E.ClassName, ': ', E.Message );
end;
ReadLn;
end.
答案 1 :(得分:1)
TDictionary
上没有迭代器返回对值的引用。所有迭代器都提供了值,这意味着当前设计无法满足您的要求。
在其他语言中,例如我所知道的C ++和D,引用是该语言中的一等公民。您可以轻松编写枚举引用而不是值的迭代器。这就是您简明扼要地解决问题所需要的。不幸的是语言缺乏。
一个明显的选择是切换到使用引用类型(类)而不是值类型(记录)。这将解决笔划中的迭代问题,因为它会迭代引用。但是,人们通常选择使用值类型是有充分理由的,并且您可能有约束阻止您进行此切换。
另一种可能性是编写一个提供迭代器的容器,该迭代器提供指向值的指针。这与您可以获得对记录的引用一样接近。但是你必须自己滚动容器。