23 октября 2020

Просмотр элементов TDictionary и TObjectDictionary

 - Здесь вместо 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;
В результате выполнения процедуры в консоль будет выведено:
Delphi TDictionary
Класс 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;

1 комментарий:

  1. Объекты автоматически уничтожаются не только при уничтожении TObjectDictionary, но и при удалении элементов.
    Так же важно, что Dictionary возвращает копию элемента. А это значит, что вносить в него изменения бесполезно. В этом случает может быть проще воспользоваться TObjectDictionary.

    ОтветитьУдалить