我有一个OleVariant
或Variant
值,例如,它是用IXMLNode.GetAttributeNS
读取的,使其成为"字符串"(varOleStr
或varString
(,我想用TRTTIField.SetValue
写入该值,例如需要与TRTTIField.FieldType: TRTTIType
兼容的TValue
赋值。
对于基本类型(沿着TVarType
和TRTTIType.TypeKind: TTypeKind
(,我正在寻找一种从OleVariant
或Variant
转换为TValue
的通用方法,而不是将每种类型都设为一个单独的情况:case VarType(Value) and varTypeMask of varXXXX: ... end
,然后将其与特定的TRTTIType
进行分配兼容。
如何在Variant和RTTI世界之间转换值?
此外,Spring4D库也是该项目的一部分,以防有帮助。
更新:
从技术上讲,我正在以下代码中寻找Convert
(在变体世界中转换(:
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
/布尔,tkFloat
,。。。如CCD_ 24所给出的。
如何使用RTTI分配变量?或者,如何将变量转换为T值,然后进行赋值?
注意:如果字段类型和值类型的性质不同,则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;
TValue中的内置类型转换在这里对您没有帮助,因为它们只允许显式兼容(即可赋值(的类型。从技术上讲,如果您将Variant存储在TValue中而不"拆包"它(FromVariant
在内部所做的(,它应该能够将Variant强制转换为通常可以强制转换/转换为的任何类型。但是,将持有"True"或"False"的Variant强制为布尔值至少有一个问题(请参阅https://quality.embarcadero.com/browse/RSP-20160)
然而,由于您已经在使用Spring4D,您可以使用其改进的TValue类型转换功能。
只需使用Spring.pas
中TValueHelper
的Convert
方法。
在那里,您可以传递一个PTypeInfo(在代码中为Left.FieldType.Handle
(和一个可选的TFormatSettings
——默认情况下,它将使用当前区域设置。
在Variant和RTTI世界之间转换值的方法是什么?
在System中使用内置的类函数转换。RTTI。T值:
myTValue := TValue.FromVariant(myVariant);
从Variant值构建新的TValue记录。
FromVariant是一种静态方法,可用于使用存储的Variant值构建TValue记录。Value参数包含将存储在构建的TValue记录中的Variant。