Delphi: как использовать TObjectList‹T›?

Мне нужно понять, как использовать универсальный Delphi 2009 TObjectList. Моя не-TObjectList попытка выглядела как

TSomeClass = class(TObject)
private
  FList1: Array of TList1;
  FList2: Array of TList2;
public
  procedure FillArray(var List: Array of TList1; Source: TSource); Overload;
  procedure FillArray(var List: Array of TList2; Source: TSource); Overload;
end;

Здесь TList1 и TList2 наследуют один и тот же конструктор constructor TParent.Create(Key: string; Value: string);. Однако из-за разной специализации (например, разных приватных полей) они не будут одного типа. Поэтому мне нужно написать два почти идентичных метода заполнения:

procedure TSomeClass.FillArray(var List: Array of TList1; Source: TSource);
begin
  for i := 0 to Source.List1.Count - 1 do begin
    SetLength(List, Length(List) + 1);
    List[i] := TList1.Create(Source.List1[i].Key, Source.List1[i].Value);
  end;
end;

с FillArray(List: Array of TList2; Source: TSource); идентичными, за исключением замены TList1 на TList2 повсюду. Насколько я понимаю, это можно аккуратно обойти, используя TObjectList и единственный метод заполнения; тем не менее, я понятия не имею, как это сделать. У кого-нибудь есть хорошие указатели на это? Спасибо!


person conciliator    schedule 02.11.2009    source источник
comment
1. TClass — очень плохой выбор для имени класса. 2. List не объявлен как var в FillChar.   -  person Uwe Raabe    schedule 02.11.2009
comment
3. УстановитьДлина(Список, Длина(Список)); на самом деле ничего не делает   -  person Uwe Raabe    schedule 02.11.2009
comment
Уве: да, это очень плохое имя. Отредактировал это и другие предложения. :)   -  person conciliator    schedule 02.11.2009


Ответы (3)


Вы не сможете сжать это, используя общий список, поскольку универсальный тип является частью определения класса. Таким образом, TObjectList<TMyClass1> отличается (и несовместимо) с TObjectList<TMyClass2>. Основным преимуществом использования универсальных списков по сравнению с обычными TList/TObjectList является повышенная безопасность типов с меньшим количеством приведений типов и более чистым кодом.

Кроме того, если вы используете пары ключ/значение, помещаете ли вы их в список, а затем извлекаете их путем поиска ключа и возврата связанного значения? Если это так, взгляните на TDictionary в Generics.Collections. Это общая хэш-таблица ключей/значений, которая значительно упростит вам этот процесс.

person Mason Wheeler    schedule 02.11.2009
comment
Спасибо Мейсон. Это отвечает на мой вопрос. - person conciliator; 02.11.2009

Официальная Wiki документации Embarcadero в Generics.Collections.TObjectList содержит простой пример кода TObjectList в действии.

Я не уверен, к чему именно ведет вопрос, но для решения широкого использования TObjectList пример кода инициализации для TObjectList может выглядеть так:

var
  List: TObjectList<TNewObject>;
  Obj: TNewObject;
begin
  { Create a new List. }
  List := TObjectList<TNewObject>.Create();

  { Add some items to the List. }
  List.Add(TNewObject.Create('One'));
  List.Add(TNewObject.Create('Two'));

  { Add a new item, but keep the reference. }
  Obj := TNewObject.Create('Three');
  List.Add(Obj);

пример кода должен дать вам представление о том, что может делать TObjectList, кроме Если я правильно понял вопрос, кажется, что вы хотели бы иметь возможность добавлять более одного типа класса к одному экземпляру TObjectList? TObjectList можно инициировать только с одним типом, поэтому может быть лучше, если вы инициируете TObjectList с интерфейсным или абстрактным классом, который является общим для всех классов, которые вы хотите добавить к нему.

Одно важное отличие при использовании TObjectList по сравнению с созданием собственного — это существование свойства OwnsObjects, которое сообщает TObjectList, владеет ли он объектами, которые вы добавляете в него, и, следовательно, должен ли он управлять освобождением их себе.

person jamiei    schedule 02.11.2009
comment
Привет Джейми. Я видел пример, о котором вы говорите. К сожалению, это не так подробно, как хотелось бы, многое осталось недосказанным. В частности, я хотел бы заполнить два разных списка, используя практически один и тот же код. Однако, как указал Мейсон, это невозможно. Итак, Overload-bonanza, вот и я! - person conciliator; 02.11.2009
comment
Ах, я так и думал, поэтому я сказал, что ObjectList может быть инициирован только с одним типом, поэтому, если возможно, вам придется изменить классы, чтобы получить интерфейс или базовый класс, чтобы это работало. - person jamiei; 02.11.2009

Что-то вроде этого?

TSomeClass = class
private
  FList1: TArray<TList1>;
  FList2: TArray<TList2>;
public
  procedure FillArray<T>(var List: TArray<T>; Source: TSource);
end;

procedure TSomeClass.FillArray<T>(var List: TArray<T>; Source: TSource);
begin
  for i := 0 to Source.List1.Count - 1 do begin
    SetLength(List, Length(List) + 1);
    List[i] := T.Create(Source.List1[i].Key, Source.List1[i].Value);
  end;
end;

Это или что-то вроде этого должно делать то, что вы хотите.

person TrespassersW    schedule 02.11.2009