有没有一种简洁的方式来更新记录的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 

只是要清楚,我知道如何用更多的代码来实现这一点,我在寻找简洁易读的东西。

+0

您可以使用TDictionary 。值 – 2013-03-01 21:59:39

+0

您希望能够修改for循环中的键或值吗?如果你只是想操作数值 – Petesh 2013-03-01 22:00:24

+0

@SirRufo,Values是只读启动器 – 2013-03-01 22:04:06

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

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

一个明显的选择是切换到使用引用类型(类)而不是值类型(记录)。这将解决中风中的迭代问题,因为它将迭代引用。然而,人们通常选择使用价值类型是有原因的,而且您可能会遇到阻碍您进行此类转换的限制。

另一种可能性是编写一个容器,该容器提供了提供指向值的指针的迭代器。这与您可以获得对记录的引用尽可能接近。但是你将不得不推出自己的容器。

+0

该死的,这不是我希望的答案。 – 2013-03-01 23:45:55

+0

这将是丑陋的,但我不知道你是否可以通过制作指向记录的TDictionary来解决这个问题。 (Gross,我知道) – 2013-03-02 12:47:09

+0

@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

+1可怕的是,我们需要跳过这样的箍... – 2013-03-02 09:26:23