delphi - 如何使用 RTTI 分配 OleVariant?//将 OleVariant 或 Variant 转换为具有特定 TTypeKind 或 TRTTIType 的 TValue?

标签 delphi rtti variant spring4d

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

对于基本类型(沿 TVarTypeTRTTIType.TypeKind: TTypeKind ),而不是使每个单独的情况:case VarType(Value) and varTypeMask of varXXXX: ... end , 我正在寻找从 OleVariant 转换的通用方法或 VariantTValue然后与特定的 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/ bool ,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;

最佳答案

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

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

只需使用 Convert来自 TValueHelper 的方法在 Spring.pas .

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

关于delphi - 如何使用 RTTI 分配 OleVariant?//将 OleVariant 或 Variant 转换为具有特定 TTypeKind 或 TRTTIType 的 TValue?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51666173/

相关文章:

delphi - 在不使用另存为的情况下更改 Delphi 2007 中的当前保存/默认目录

multithreading - 在 TThread 上创建 MainForm

c# - 避免 NULL 检查的 C# 运行时类型识别的简化方法?

c++ - directory_entry 的输出与具有变体的类的重载 ostream 运算符<< 冲突

delphi - Rtti 的自由对象字段

Delphi 没有足够的 RTTI 可用于支持此操作

c++ - 给定一个 DDS 主题名称,是否可以在运行时确定主题类型信息?

Android Gradle 插件(警告)API 'variant.getMergeResources()' 已过时并已替换为 'variant.getMergeResourcesProvider()'

c++ - 字节数组到 Variant

delphi - E2010 不兼容类型,为什么?