При работе с компонентами VCL в Delphi может возникнуть ситуация, когда при обращении к свойствам через TRttiContext.GetType некоторые из них отображаются несколько раз. Это связано с особенностями наследования свойств в объектно-ориентированном программировании, когда свойства могут быть переопределены в дочерних классах с измененной видимостью или порядком.
Пример кода, вызывающего проблему
В приведенном ниже коде используется TRttiContext для получения списка свойств компонента VCL:
uses
System.RTTI,
System.Generics.Collections,
System.Generics.Defaults;
procedure TForm11.btnShowPropertiesClick(Sender: TObject);
var
R: TRttiContext;
Props: TArray<TRttiProperty>;
Prop: TRttiProperty;
begin
Memo1.Clear;
R := TRttiContext.Create;
Props := R.GetType(Sender.ClassType).GetProperties;
// Сортировка свойств по имени
TArray.Sort<TRttiProperty>(Props,
TComparer<TRttiProperty>.Construct(
function(const Left, Right: TRttiProperty): Integer
begin
Result := CompareText(Left.Name, Right.Name);
end
)
);
for Prop in Props do
begin
try
Memo1.Lines.Add(
Prop.Name + ' : ' +
Prop.PropertyType.ToString + ' = ' +
Prop.GetValue(Sender).ToString);
except
Memo1.Lines.Add(Prop.Name + ' generated an exception');
end;
end;
end;
При выполнении этого кода в компоненте Memo1 отображаются свойства, некоторые из которых повторяются, например, Action и Align.
Объяснение проблемы
Проблема заключается в том, что метод GetProperties возвращает свойства, которые были переопределены в дочерних классах с более высокой видимостью или измененным порядком. Это типично для компонентов, когда базовый класс определяет свойство с защищенной видимостью, а дочерний класс переопределяет его с опубликованной.
Подтвержденный ответ
Для решения проблемы можно добавить в цикл, который заполняет Memo1, информацию о родительском классе свойства:
for Prop in Props do
begin
try
Memo1.Lines.Add(
Prop.Parent.QualifiedName + '.' + Prop.Name + ' : ' +
Prop.PropertyType.ToString + ' = ' +
Prop.GetValue(Sender).ToString);
except
Memo1.Lines.Add(Prop.Name + ' generated an exception');
end;
end;
Таким образом, в выводе будет отображаться полное имя свойства, включая класс, к которому оно принадлежит. Это позволит увидеть, что свойства могут быть переопределены в дочерних классах.
Альтернативный ответ
Использование метода GetDeclaredProperties может быть более полезным, так как он возвращает список свойств, объявленных непосредственно в отраженном типе, без учета наследованных свойств.
Заключение
Повторение свойств при использовании TRttiContext.GetType является ожидаемым поведением и связано с особенностями наследования в объектно-ориентированном программировании. Для решения этой проблемы можно использовать дополнительную информацию о родительских классах свойств или применять метод GetDeclaredProperties, который возвращает только собственные свойства класса.
В процессе работы с компонентами VCL в Delphi через отражение типов RTTI может возникнуть повторное отображение свойств из-за особенностей наследования, что требует корректировки подхода для получения уникального списка свойств.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.