- Здесь вместо TStringList.AddObject было бы лучше использовать TObjectDictionary. | |
- Не могу. Мне надо получить список всех объектов, а у TDictionary нельзя обратиться к его элементу по индексу... |
С выпуском Delphi 2009 язык программирования Delphi получил новый элемент языка – дженерики (generics). Дженерики позволяют описать класс, у которого типы обрабатываемых данных задаются в качестве параметров при объявлении экземпляра класса. Поэтому такие классы могут называть параметризованными типами. Delphi хранит свой набор дженериков в модуле System.Generics.Collections. Среди них есть TDictionary – это набор пар "ключ-значение", которые могут быть любых типов. В отличии от привычного TStringList, у TDictionary нет свойств Strings, Objects, Names, KeyNames и ValueFromIndex к которым можно получить доступ по индексу. Но это не значит, что нельзя получить список его ключей и значений.
Создадим экземпляр класса TDictionary<string, string>, заполним его и выведем его ключи и значения в консоль:
procedure TestDictionary; var dict: TDictionary<string, string>; begin dict := TDictionary<string, string>.Create; try dict.Add('Key1', 'Value1'); dict.Add('Key2', 'Value2'); WriteLn('Ключи:'); for var sKey: String in dict.Keys do Writeln(sKey); WriteLn('Значения:'); for var sValue: String in dict.Values do Writeln(sValue); WriteLn('Пары "ключ-значение":'); for var sKey in dict.Keys do Writeln(sKey, ' = ', dict.Items[sKey]); finally dict.Free end; end;В результате выполнения процедуры в консоль будет выведено: Класс TDictionary в unit System.Generics.Collections описан так:
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)Поэтому будет правильно при выводе пары "ключ-значение" обратиться к его элементу, как к паре (TPair<TKey,TValue>):
WriteLn('Пары "ключ-значение":'); for var rec: TPair<string, string> in dict do Writeln(rec.Key, ' = ', rec.Value);Среди стандартных дженериков в Delphi есть наследуемый от TDictionary класс, у которого ключ и/или значение должны быть объектом - TObjectDictionary. Единственным его отличием от TDictionary является то, что он при своем уничтожении умеет автоматически высвобождать память объектов ключ/значение. При создании экземпляра TObjectDictionary программист указывает, что необходимо уничтожать при его уничтожении: объекты ключей, объекты значений или всю пару. Доступ к его элементам TObjectDictionary аналогичен доступу к элементам TDictionary:
type TXyz = class private FValue: String; public property asString: String read FValue; constructor Create(const iValue: Integer); end; constructor TXyz.Create(const iValue: Integer); begin inherited Create; FValue := 'Value ' + iValue.ToString end; procedure TestObjectDictionary; var dict: TObjectDictionary<string, TXyz>; begin dict := TObjectDictionary<string, TXyz>.Create([doOwnsValues]); try dict.Add('Key1', TXyz.Create(1)); dict.Add('Key2', TXyz.Create(2)); WriteLn('Ключи:'); for var sKey: String in dict.Keys do Writeln(sKey); WriteLn('Значения:'); for var Value: TXyz in dict.Values do Writeln(Value.asString); WriteLn('Пары "ключ-значение":'); for var sKey in dict.Keys do Writeln(sKey, ' = ', dict.Items[sKey].asString); WriteLn('Пары "ключ-значение":'); for var rec: TPair<string, TXyz> in dict do Writeln(rec.Key, ' = ', rec.Value.asString); finally dict.Free end; end;
Объекты автоматически уничтожаются не только при уничтожении TObjectDictionary, но и при удалении элементов.
ОтветитьУдалитьТак же важно, что Dictionary возвращает копию элемента. А это значит, что вносить в него изменения бесполезно. В этом случает может быть проще воспользоваться TObjectDictionary.