如何使用 RTTI 分配 OleVariant? // 将 OleVariant 或 Variant 转换为具有特定 TTypeKind 或 TRTTIType 的 TValue?
How to assign an OleVariant with RTTI? // Convert an OleVariant or a Variant to a TValue with specific TTypeKind or TRTTIType in mind?
我有一个 OleVariant
或 Variant
值,例如,用 IXMLNode.GetAttributeNS
读取,使其成为 "String"(varOleStr
或varString
),我想写那个值,例如 TRTTIField.SetValue
,需要 TValue
分配兼容 TRTTIField.FieldType: TRTTIType
。
对于基本类型(以及 TVarType
和 TRTTIType.TypeKind: TTypeKind
),我不是将每个都设为单个案例:case VarType(Value) and varTypeMask of varXXXX: ... end
,而是寻找一种从 [= 转换的通用方法12=] 或 Variant
到 TValue
然后与特定的 TRTTIType
.
赋值兼容
在 Variant 和 RTTI 世界之间转换值的方式是什么?
此外,Spring4D 库是项目的一部分,以防有帮助。
更新:
从技术上讲,我在以下代码中寻找 Convert
(在 Variant 世界中转换):
var
Left: TRTTIField;
Right: OleVariant;
Temp: TValue;
Instance: Pointer;
begin
{ Examples: varOleStr --> varXXXX --> assignment-compatible TValue }
Right := 'False'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varBoolean
Temp := TValue.FromVariant(Right); // tkEnumeration, like Left.FieldType.TypeKind
Right := '2'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varInteger
Temp := TValue.FromVariant(Right); // tkInteger, like Left.FieldType.TypeKind
Right := '3.1415'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varDoiuble
Temp := TValue.FromVariant(Right); // tkFloat, like Left.FieldType.TypeKind
Right := 'Hello!'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varOleStr
Temp := TValue.FromVariant(Right); // tkUString, like Left.FieldType.TypeKind
{ ... and an assignment: }
Left.SetValue(Instance, Temp);
end;
我找到了 VariantChangeTypeEx
,但是,我不知道如何将 Left.FieldType
关联到它以使后续代码工作。 -- 我也不介意在 RTTI 世界中进行转换,而是从 Temp := TValue.FromVariant(Right)
(tkUString
) 开始,然后以某种方式达到分配兼容性;所以 Temp.Kind
会变成 tkEnumeration
/Boolean, tkFloat
,... 由 Left.FieldType.TypeKind
.
给出
如何使用 RTTI 分配变体?或者,如何将 Variant 转换为 TValue 然后赋值?
注意:如果字段类型和值类型在性质上不同,RTTIField.SetValue
将失败并返回 EInvalidCast
,因为 RTTI 不会尝试更改值的性质。我这里的困难是达到分配兼容性。
更新:鉴于答案,以下代码勾勒出我的解决方案:
procedure (const Value: Pointer; const RTTIField: TRTTIField; const XMLNode: IXMLNode);
var
Temp1: OLEVariant;
Temp2: TValue;
begin
Assert(XMLNode.HasAttribute(Ref, Namespace));
Temp1 := XMLNode.GetAttributeNS(Ref, Namespace);
Temp2 := TValue.FromVariant(Temp1);
Temp2 := Temp2.Convert(RTTIField.FieldType.Handle{, FormatSettings}); // in Spring.TValueHelper
RTTIField.SetValue(Value, Temp2);
end;
What is the way to transition values between the Variant and the RTTI world?
在System.RTTI.TValue中使用内置的class函数转换:
myTValue := TValue.FromVariant(myVariant);
Builds a new TValue record from a Variant value.
FromVariant is a static method that can be used to build TValue records with a stored Variant value. The Value parameter contains the Variant that will be stored inside the built TValue record.
TValue 中的内置类型转换在这里对您没有帮助,因为它们只允许那些明确兼容(即可分配)的类型。从技术上讲,如果您将 Variant 存储在没有 "unpacking" 的 TValue 中,这是 FromVariant
在内部所做的,它应该能够将 Variant 转换为通常可以 cast/converted 的任何内容。但是,将持有 'True' 或 'False' 的 Variant 转换为布尔值至少存在一个问题(参见 https://quality.embarcadero.com/browse/RSP-20160)
然而,由于您已经在使用 Spring4D,因此您可以使用其改进的 TValue 类型转换功能。
只需使用 Spring.pas
中 TValueHelper
的 Convert
方法即可。
您可以在那里传递一个 PTypeInfo(在您的代码中为 Left.FieldType.Handle
)和一个可选的 TFormatSettings
- 默认情况下它将使用当前语言环境。
我有一个 OleVariant
或 Variant
值,例如,用 IXMLNode.GetAttributeNS
读取,使其成为 "String"(varOleStr
或varString
),我想写那个值,例如 TRTTIField.SetValue
,需要 TValue
分配兼容 TRTTIField.FieldType: TRTTIType
。
对于基本类型(以及 TVarType
和 TRTTIType.TypeKind: TTypeKind
),我不是将每个都设为单个案例:case VarType(Value) and varTypeMask of varXXXX: ... end
,而是寻找一种从 [= 转换的通用方法12=] 或 Variant
到 TValue
然后与特定的 TRTTIType
.
在 Variant 和 RTTI 世界之间转换值的方式是什么?
此外,Spring4D 库是项目的一部分,以防有帮助。
更新:
从技术上讲,我在以下代码中寻找 Convert
(在 Variant 世界中转换):
var
Left: TRTTIField;
Right: OleVariant;
Temp: TValue;
Instance: Pointer;
begin
{ Examples: varOleStr --> varXXXX --> assignment-compatible TValue }
Right := 'False'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varBoolean
Temp := TValue.FromVariant(Right); // tkEnumeration, like Left.FieldType.TypeKind
Right := '2'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varInteger
Temp := TValue.FromVariant(Right); // tkInteger, like Left.FieldType.TypeKind
Right := '3.1415'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varDoiuble
Temp := TValue.FromVariant(Right); // tkFloat, like Left.FieldType.TypeKind
Right := 'Hello!'; // varOleStr, as read with IXMLNode.GetAttributeNS
Right := Convert(Right, Left.FieldType); // making it possibly varOleStr
Temp := TValue.FromVariant(Right); // tkUString, like Left.FieldType.TypeKind
{ ... and an assignment: }
Left.SetValue(Instance, Temp);
end;
我找到了 VariantChangeTypeEx
,但是,我不知道如何将 Left.FieldType
关联到它以使后续代码工作。 -- 我也不介意在 RTTI 世界中进行转换,而是从 Temp := TValue.FromVariant(Right)
(tkUString
) 开始,然后以某种方式达到分配兼容性;所以 Temp.Kind
会变成 tkEnumeration
/Boolean, tkFloat
,... 由 Left.FieldType.TypeKind
.
如何使用 RTTI 分配变体?或者,如何将 Variant 转换为 TValue 然后赋值?
注意:如果字段类型和值类型在性质上不同,RTTIField.SetValue
将失败并返回 EInvalidCast
,因为 RTTI 不会尝试更改值的性质。我这里的困难是达到分配兼容性。
更新:鉴于答案,以下代码勾勒出我的解决方案:
procedure (const Value: Pointer; const RTTIField: TRTTIField; const XMLNode: IXMLNode);
var
Temp1: OLEVariant;
Temp2: TValue;
begin
Assert(XMLNode.HasAttribute(Ref, Namespace));
Temp1 := XMLNode.GetAttributeNS(Ref, Namespace);
Temp2 := TValue.FromVariant(Temp1);
Temp2 := Temp2.Convert(RTTIField.FieldType.Handle{, FormatSettings}); // in Spring.TValueHelper
RTTIField.SetValue(Value, Temp2);
end;
What is the way to transition values between the Variant and the RTTI world?
在System.RTTI.TValue中使用内置的class函数转换:
myTValue := TValue.FromVariant(myVariant);
Builds a new TValue record from a Variant value.
FromVariant is a static method that can be used to build TValue records with a stored Variant value. The Value parameter contains the Variant that will be stored inside the built TValue record.
TValue 中的内置类型转换在这里对您没有帮助,因为它们只允许那些明确兼容(即可分配)的类型。从技术上讲,如果您将 Variant 存储在没有 "unpacking" 的 TValue 中,这是 FromVariant
在内部所做的,它应该能够将 Variant 转换为通常可以 cast/converted 的任何内容。但是,将持有 'True' 或 'False' 的 Variant 转换为布尔值至少存在一个问题(参见 https://quality.embarcadero.com/browse/RSP-20160)
然而,由于您已经在使用 Spring4D,因此您可以使用其改进的 TValue 类型转换功能。
只需使用 Spring.pas
中 TValueHelper
的 Convert
方法即可。
您可以在那里传递一个 PTypeInfo(在您的代码中为 Left.FieldType.Handle
)和一个可选的 TFormatSettings
- 默认情况下它将使用当前语言环境。