| - Здесь вместо 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.