Delphi: updating a (potentially non-existing) item in a generic TDictionary: use ExtractPair. Except in Delphi 2010/XE.
Posted by jpluimers on 2018/11/06
“Documented” in Delphi 2010, [Archive.is] Generics.Collections.TDictionary.ExtractPair – RAD Studio VCL Reference, and functioning bug-free since Delphi XE2, but still hardly documented, [Archive.is] System.Generics.Collections.TDictionary.ExtractPair – XE2 API Documentation is the easiest way to get a value out of a dictionary and updating it, even if it does not exist.
ExtractPair extracts the TPair<TKey, TValue> if it exists (and removes it from the dictionary) or returns a Default initialised one if not. Though Default is still not documented, you can find an example at [WayBack] How to properly free records that contain various types in Delphi at once? – Stack Overflow.
Example code for ExtractPair:
FEceptionDictionary := TDictionary<TExceptionKey, Integer>.Create();
...
var
ExceptionCountPair: TPair<TExceptionKey,Integer>;
begin
TMonitor.Enter(FEceptionDictionary);
try
ExceptionCountPair := FEceptionDictionary.ExtractPair(ExceptObj.ClassType); // extracts and removed from dictionary!
FEceptionDictionary.Add(ExceptionCountPair.Key, ExceptionCountPair.Value + 1); // use Value as count
finally
TMonitor.Exit(FEceptionDictionary);
end;
end;
In Delphi 2010 and XE it was buggy (see [WayBack] QualityCentral 80947: TDictionary.ExtractPair Fails and creates memory leak via [WayBack] generics – Delphi TPair Exception – Stack Overflow), but since then it works fine, and now is properly documented:
[WayBack] System.Generics.Collections.TDictionary.ExtractPair – RAD Studio API Documentation
Returns the
TPair<TKey,TValue>pair with the specifiedKeyand [WayBack] removes the returned pair from a dictionary.If the dictionary does not contain the specified
Key, the returned pair contains a defaultTValue.
–jeroen






David Heffernan said
This is a terrible design. It means you can’t tell whether or not there was a value already in the collection. They need a TryExtract, just as we added to the spring dict.
jpluimers said
Yup, it is, and this code should soon be migrated to use Spring4D.
Thanks for pointing this out.
Remy said
You don’t need to extract a pair in order to update a value.
TDictionary‘sTryGetValue()method also returns a defaulted value if the key does not exist (and yes, that is documented behavior), andTDictionaryalso has anAddOrSetValue()method to update an existing key with a new value.jpluimers said
I will give this a try.
rvelthuis said
Inded. That is actually the usual way to do this. Extracting and then re-inserting a pair sounds hackish.