有没有一种简洁的方式来更新记录的TDictionary中的所有值?
我想要做这样的事情,但它不会编译,因为Pair不能分配给。有没有一种简洁的方式来更新记录的TDictionary中的所有值?
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
只是要清楚,我知道如何用更多的代码来实现这一点,我在寻找简洁易读的东西。
TDictionary
上没有迭代器,它返回对值的引用。所有的迭代器都提供了值,这意味着你所要求的是当前设计所不可能的。
在其他语言中,例如我知道的C++和D,引用是该语言中的第一类公民。您可以轻松地编写枚举引用而不是值的迭代器。这就是你需要简洁地解决你的问题。不幸的是,这种语言缺乏。
一个明显的选择是切换到使用引用类型(类)而不是值类型(记录)。这将解决中风中的迭代问题,因为它将迭代引用。然而,人们通常选择使用价值类型是有原因的,而且您可能会遇到阻碍您进行此类转换的限制。
另一种可能性是编写一个容器,该容器提供了提供指向值的指针的迭代器。这与您可以获得对记录的引用尽可能接近。但是你将不得不推出自己的容器。
该死的,这不是我希望的答案。 – 2013-03-01 23:45:55
这将是丑陋的,但我不知道你是否可以通过制作指向记录的TDictionary来解决这个问题。 (Gross,我知道) – 2013-03-02 12:47:09
@Warren但谁拥有这些记录?你必须为他们有一个单独的容器。 – 2013-03-03 08:29:16
下面是一个简单的程序,它显示了使用记录和对象与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可怕的是,我们需要跳过这样的箍... – 2013-03-02 09:26:23
您可以使用TDictionary。值 –
2013-03-01 21:59:39
您希望能够修改for循环中的键或值吗?如果你只是想操作数值 – Petesh 2013-03-01 22:00:24
@SirRufo,Values是只读启动器 – 2013-03-01 22:04:06