Delphi 是否有一种简洁的方法来更新记录字典中的所有值?

Delphi 是否有一种简洁的方法来更新记录字典中的所有值?,delphi,Delphi,我想这样做,但它不会编译,因为不能将Pair分配给 var MyDictionary: TDictionary<TGuid, TCustomRecord>; Pair: TPair<TGuid, TCustomRecord>; begin // ... create and populate my dictionary ... foreach Pair in MyDictionary do begin PairRef.Value.MyFiel

我想这样做,但它不会编译,因为不能将Pair分配给

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
var
我的字典:t字典;
配对:TPair;
开始
// ... 创建并填充我的字典。。。
我字典里的每一对都有
开始
PairRef.Value.MyField:=PairRef.Value.MyField+1;
结束;
结束

为了清楚起见,我知道如何用更多的代码来实现这一点,我正在寻找简洁易读的东西。

下面是一个简单的程序,它显示了使用带有
t字典的记录和对象的不同处理

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;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils、System.Generics.Collections;
类型
TMyRecord=记录
字段:整数;
结束;
TMyObject=class
字段:整数;
结束;
程序使用对象dict;
变量
LDict:t词典;
左值:TMyObject;
开始
写入('TMyObject:');
LDict:=TObjectDictionary.Create([DoownsValue]);
尝试
//填充
而LDict.Count<10 do
开始
LDict.Add(TGuid.NewGuid,TMyObject.Create);
结束;
//更新
对于LDict中的左值。值为
开始
左值字段:=左值字段+1;
结束;
//输出
对于LDict中的左值。值为
开始
写入(左值字段',');
结束;
书面语;
最后
免费下载;
结束;
结束;
程序用户记录;
变量
LDict:t词典;
LKey:TGUID;
左值:TMyRecord;
开始
写('TMyRecord:');
LDict:=TDictionary.Create;
尝试
//填充
而LDict.Count<10 do
开始
左值字段:=0;
LDict.Add(TGuid.NewGuid,左值);
结束;
//更新
对于LKey在LDict。钥匙可以
开始
左值。字段:=LDict[LKey]。字段+1;
LDict.AddOrSetValue(LKey,左值);
结束;
//输出
对于LDict中的左值。值为
开始
写入(左值字段',');
结束;
书面语;
最后
免费下载;
结束;
结束;
开始
ReportMemoryLeaksOnShutdown:=True;
尝试
使用ObjectDict;
用户记录;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
ReadLn;
结束。

TDictionary
上没有返回值引用的迭代器。所有迭代器都提供值,这意味着当前设计不可能满足您的要求

在其他语言中,例如我所知道的C++和D,引用是语言中的第一类公民。您可以轻松编写迭代器来枚举引用而不是值。这就是你需要简明扼要地解决问题的原因。不幸的是,语言缺乏

一个明显的选择是切换到使用引用类型(类)而不是值类型(记录)。这将解决笔划中的迭代问题,因为它将在引用上迭代。然而,人们通常选择使用值类型是有很好的理由的,并且您可能会受到限制而无法进行此切换


另一种可能是编写一个提供迭代器的容器,迭代器提供指向值的指针。这是你能找到的最接近记录的引用。但是您必须滚动自己的容器。

您可以使用TDictionary.values您希望能够修改for循环中的键或值吗?如果您只想操作values@SirRufo,值是只读的enumarator@Petesh,我想更新我的值。不幸的是,您建议的方法不起作用。@Lawrence:改为使用
TObjectDictionary
,并在构造函数中传递
[doOwnsValues]
;它使
TObjectDictionary
在提取、删除或销毁
值时释放这些值(类似于
TObjectList
的行为)。然后你可以用一个类而不是一个记录,就不会有这个问题了。该死,这不是我想要的答案。这会很难看,但我想知道你是否可以通过制作一个指向记录的指针的字典来解决这个问题。(格罗斯,我知道)@Warren但是谁会拥有这些唱片呢?你必须为它们准备一个单独的容器。是的,我想一路下来都很糟糕。