2

I am using a TDictionary of <string, string>. But for some reason, the linker decides that I do not want to get items out of it.

I have the following code:

function TSheet.GetFieldName(Field: string; Default: string): string;
begin
  Result := Default;
  if FFieldNames[Field] = '' then
    Result := Field
  else
    Result := FFieldNames[Field];
end;

FFieldNames is a TDictionary<string, string>. On line 2 (if FFieldNames[Field] = '' then), it throws a 'File not found' exception. Adding FFieldNames[Field] to my watch tells me that Function to be called, {System.Generics.Collections}TDictionary.GetItem, was eliminated by linker.

Someone asked here on a similar issue on how to avoid the linker eliminating functions during debugging. From this I gathered, that the compiler/linker assumes that I am not using it. Someone suggested - during conversation - that I should try using it more.

So I created the following code:

FFieldNames.Add(Name, S);
V := FFieldNames.Items[Name];

Where S, Name and V are strings. This is from the code where FFieldNames is filled with data. V's only purpose is to obtain the just inserted S; it does nothing else.

Strangely, while the debugger tells me the same thing (i.e. GetItem being eliminated), V does get set to the expected value. But it does not in my TSheet.GetFieldName function. :|

What am I missing?

Community
  • 1
  • 1
Svip
  • 2,958
  • 3
  • 22
  • 33
  • 1
    I think your code is wrong anyway. If the key is not present then using `Items[]` will lead to an exception. You need `TryGetValue`. And you also need to make sure that you don't lookup the value twice. You want `if not FFieldNames.TryGetValue(Field, Result) then Result := Field;` Or perhaps what you mean is `if not FFieldNames.TryGetValue(Field, Result) then Result := Default;`. Also, `Result := Default` is pointless since you always overwrite. The compiler will tell you that if you switch on warnings. – David Heffernan Mar 08 '13 at 09:52
  • This error only happens in the debugger which seems to get confused with generics. Your error is definitely not caused by the linker. – jpfollenius Mar 08 '13 at 10:18
  • I realised my error just moments after I posted it; using `ContainsKey()` made it work! But Heffernan's suggestion of `TryGetValue` is also a good idea. Thanks for that. – Svip Mar 08 '13 at 10:48
  • 1
    I invariably find that I only ever use `TryGetValue`. Perhaps it's something about the dicts that I use, but I always want to handle the case of key not in dict using a boolean test rather than an exception. And I want to lookup the value and test for key in dict in a single operation for efficiency. Which means that I only ever use `TryGetValue`. – David Heffernan Mar 08 '13 at 11:09

1 Answers1

-1

The same problem applies to TList<>. Even if the code is using a method in the class it is not accessible from the debugger ("xxx on TList eliminated by linker"). I guess this is a problem with generics in general.

If you make a descendent class it will not have this problem

type
  TMyList = class(TList<TMyObject>)

  end;

var
  List : TMyList;
begin
  ...

end;
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
AgoraC
  • 9
  • 1
  • 2
  • Nice idea, but I tried this approach on TDictionary and it didn't work. The relevant access methods were still eliminated by the linker. – Josh Doebbert Apr 23 '20 at 18:47