В данной статье мы рассмотрим вопрос о проверке и создании пользовательского Variant для типа TBcd с помощью метода TValue.AsVariant. Мы также предложим решение этой проблемы, а затем рассмотрим альтернативное решение.
Контекст:
Дмитрий Б. задал вопрос о том, как проверить наличие соответствующего пользовательского типа Variant для определенного записи (record) типа и вызвать создание соответствующего пользовательского значения Variant при вызове TValue.AsVariant для типа TBcd. Он столкнулся с ошибкой "Неверное преобразование класса" при попытке выполнить это.
Рейми Лебо, другой участник дискуссии, объяснил, что TValue progettato per mimare solo le conversione che il compilatore stesso può eseguire implicitamente. I Custom variant non rientrano in questa area. Non ci sono conversione implicite tra TBcd e Variant, devi usare funzioni esplicite (ad esempio VarFMTBcdCreate() e VarToBcd()), che TValue non può chiamare internamente per te. Questo è il motivo per cui ottieni l’errore "Nessun cast di classe valido".
Решение:
Чтобы проверить наличие соответствующего пользовательского типа Variant для определенного записи (record) типа и вызвать создание соответствующего пользовательского значения Variant при вызове TValue.AsVariant, вы можете использовать следующий подход:
Создайте пользовательский тип Variant для типа TBcd, если он еще не создан.
Проверьте, является ли текущий тип Variant пользовательским типом Variant для типа TBcd с помощью TRttiType и TRttiProperty.
Если это так, вызовите TValue.AsVariant, чтобы создать соответствующее пользовательское значение Variant.
Пример кода на Object Pascal (Delphi):
uses
System.SysUtils,
System.Types,
TypInfo,
System.UITypes,
System.Classes,
System.Variants,
Data.FmtBcd;
type
TFMTBcdVariantType = record
VarData: TBcd;
constructor Create(const AValue: TBcd);
end;
constructor TFMTBcdVariantType.Create(const AValue: TBcd);
begin
VarData := AValue;
end;
type
TListItemObj = class(TPersistent)
private
FSecondName: String;
FFirstName: String;
FAge: Integer;
FBigUInt: UInt64;
FFmtBcd: TBcd;
public
property FirstName: String read FFirstName write FFirstName;
property SecondName: String read FSecondName write FSecondName;
property Age: Integer read FAge write FAge;
property BigUInt: UInt64 read FBigUInt write FBigUInt;
property FmtBcd: TBcd read FFmtBcd write FFmtBcd;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
LType: TRttiType;
AllProps: TArray<TRttiProperty>;
Prop: TRttiProperty;
RttiContext: TRttiContext;
ValValue: TValue;
VarValue: Variant;
FmtBcdVarType: TRttiType;
ListItem: TListItemObj;
begin
ListItem := TListItemObj.Create;
with ListItem do
begin
FirstName := 'P';
SecondName := 'C';
Age := 33;
BigUInt := 12345678900987654321;
FmtBcd := 112233445566778899.000011;
end;
RttiContext := TRttiContext.Create;
LType := RttiContext.GetType(TListItemObj);
AllProps := LType.GetProperties();
FmtBcdVarType := RttiContext.GetType(TFMTBcdVariantType);
for Prop in AllProps do
begin
ValValue := Prop.GetValue(ListItem);
if Prop.Type = FmtBcdVarType then
VarValue := VarFMTBcdCreate(ValValue.AsType(TFMTBcdVariantType).VarData)
else
VarValue := ValValue.AsVariant;
end;
ListItem.Free;
end;
В этом примере мы создаем пользовательский тип Variant для типа TBcd, называемый TFMTBcdVariantType. Затем мы проверяем, является ли текущий тип Variant пользовательским типом Variant для типа TBcd с помощью TRttiType и TRttiProperty. Если это так, мы вызываем VarFMTBcdCreate(), чтобы создать соответствующее пользовательское значение Variant. В противном случае мы просто вызываем TValue.AsVariant.
Альтернативное решение:
В качестве альтернативного решения вы можете использовать функции VarFMTBcdCreate() и VarToBcd(), чтобы явно преобразовать тип TBcd в Variant и наоборот. Это избавит вас от необходимости создавать пользовательский тип Variant для типа TBcd и проверять его наличие перед вызовом TValue.AsVariant.
Пример кода на Object Pascal (Delphi):
uses
System.SysUtils,
System.Types,
TypInfo,
System.UITypes,
System.Classes,
System.Variants,
Data.FmtBcd;
type
TListItemObj = class(TPersistent)
private
FSecondName: String;
FFirstName: String;
FAge: Integer;
FBigUInt: UInt64;
FFmtBcd: TBcd;
public
property FirstName: String read FFirstName write FFirstName;
property SecondName: String read FSecondName write FSecondName;
property Age: Integer read FAge write FAge;
property BigUInt: UInt64 read FBigUInt write FBigUInt;
property FmtBcd: TBcd read FFmtBcd write FFmtBcd;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
LType: TRttiType;
AllProps: TArray<TRttiProperty>;
Prop: TRttiProperty;
RttiContext: TRttiContext;
ValValue: TValue;
VarValue: Variant;
ListItem: TListItemObj;
begin
ListItem := TListItemObj.Create;
with ListItem do
begin
FirstName := 'P';
SecondName := 'C';
Age := 33;
BigUInt := 12345678900987654321;
FmtBcd := 112233445566778899.000011;
end;
RttiContext := TRttiContext.Create;
LType := RttiContext.GetType(TListItemObj);
AllProps := LType.GetProperties();
for Prop in AllProps do
begin
ValValue := Prop.GetValue(ListItem);
if Prop.Type.Name = 'TBcd' then
VarValue := VarFMTBcdCreate(ValValue.AsType(TBcd))
else
VarValue := ValValue.AsVariant;
end;
ListItem.Free;
end;
В этом примере мы явно проверяем, является ли текущий тип Variant
Статья: 'Проверка и создание пользовательского Variant для типа TBcd с помощью TValue.AsVariant'
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.