1

我有一个OleVariantVariant值,例如,用 读取IXMLNode.GetAttributeNS,使其成为“字符串”(varOleStrvarString),我想用 写该值,例如,TRTTIField.SetValue需要与 的TValue赋值兼容TRTTIField.FieldType: TRTTIType

对于基本类型(以及TVarType和),我不是将TRTTIType.TypeKind: TTypeKind每个单独的案例:case VarType(Value) and varTypeMask of varXXXX: ... endOleVariantVariantTValueTRTTIType

在 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;
4

2 回答 2

3

TValue 中的内置类型转换在这里对您没有帮助,因为它们只允许那些显式兼容(即可分配)的类型。从技术上讲,如果您将 Variant 存储在 TValue 中而不“解包”它,这就是FromVariant在内部执行的操作,它应该能够将 Variant 转换为通常可以转换/转换为的任何内容。但是,将持有“真”或“假”的变体转换为布尔值至少存在一个问题(参见https://quality.embarcadero.com/browse/RSP-20160

但是,由于您已经在使用 Spring4D,您可以使用其改进的 TValue 类型转换功能。

只需使用in 中的Convert方法。TValueHelperSpring.pas

在那里你可以传递一个 PTypeInfo (这将Left.FieldType.Handle在你的代码中)和可选的TFormatSettings- 默认情况下它将使用当前的语言环境。

于 2018-08-03T09:53:40.263 回答
2

在 Variant 和 RTTI 世界之间转换值的方法是什么?

使用System.RTTI.TValue中的内置类函数转换:

myTValue := TValue.FromVariant(myVariant);

从 Variant 值构建新的 TValue 记录。

FromVariant是一种静态方法,可用于使用存储的 Variant 值构建 TValue 记录。Value 参数包含将存储在构建的 TValue 记录中的 Variant。

于 2018-08-03T08:09:23.433 回答