views:

75

answers:

1

Hi all,

I'm using Delphi 9's TDictionary generic class. My TDictionary looks like this:

g_FileHandlers : TDictionary<String, TList<String>>;

And, so I initialize the TDictionary like so:

g_FileHandlers := TDictionary<String, TList<String>>.Create;

I have a TList, that I'm also initializing, so that I can use it to populate the TDictionary. I'm looping over some file data which I use to populate the TList/TDictionary, and I'm trying to re-use the same TList to insert into the TDictionary as the Value. On the first insertion into the TDictionary, the TList value of the item exists and has the data in it. On the second, and subsequent iterations though the TList Values are all nil.

g_FilePaths := TList<String>.Create;

It sounds to me like it's doing all of this by reference. Does anyone know how to add a TList to my TDictionary by value, instead of reference?

Thank you

  // Create our dictionary of files and handlers
  for i := 0 to g_FileList.Count - 1 do
  begin
    g_HandlerName := AnsiMidStr(g_FileList[i], 2, Length(g_FileList[i]));
    g_HandlerName := AnsiMidStr(g_HandlerName, 1, Pos('"', g_HandlerName) - 1);

    if i = 0 then
      g_PreviousHandlerName := g_HandlerName;

    if AnsiCompareText(g_HandlerName, g_PreviousHandlerName) = 0 then
    begin
      g_FilePath := AnsiMidStr(g_FileList[i], Length(g_HandlerName) + 5, Length(g_FileList[i]));
      g_FilePath := AnsiMidStr(g_FilePath, 1, Length(g_FilePath) - 1);
      g_FilePaths.Add(g_FilePath);
    end
    else
    begin
      g_FileHandlers.Add(g_PreviousHandlerName, g_FilePaths);

      g_FilePaths.Clear;
      g_FilePath := AnsiMidStr(g_FileList[i], Length(g_HandlerName) + 5, Length(g_FileList[i]));
      g_FilePath := AnsiMidStr(g_FilePath, 1, Length(g_FilePath) - 1);
      g_FilePaths.Add(g_FilePath);
    end;

    if AnsiCompareText(g_HandlerName, g_PreviousHandlerName) <> 0 then
      g_PreviousHandlerName := g_HandlerName;

    if i = g_FileList.Count - 1 then
      g_FileHandlers.Add(g_HandlerName, g_FilePaths);
  end;
  g_FilePaths.Free;
+1  A: 

The TList "value" you have is a reference, so you are adding it by value. (Adding by reference would mean that if you changed the value of g_FilePaths, the values stored in the dictionary would change as well, but that doesn't happen — those values continue referring to the same TList object they started with.

TDictionary doesn't make deep copies of objects, just like nothing else does. You're just going to have to bite the bullet and create a new TList object for every item you wish to add. You can re-use the global variable g_FilePaths if you want, but you need to instantiate a new object each iteration.

Rob Kennedy
I agree and would also like to suggest that the OP use TObjectDictionary and create using "TObjectDictionary<string,TList<String>>.Create([doOwnsValues]);" to avoid memory leaks of the lists when items are removed.
Ville Krumlinde