将 ToString 用于 Variant 变量

Using ToString for Variant variables

以下代码产生 EVariantInvalidOpError 异常:

var
  i : Variant;
begin
  i := 10;
  ShowMessage(i.ToString());
end;

以下所有工作正常,但我不明白为什么 ToString 函数会引发 Variant 类型变量的异常:

var
  i : Variant;
begin
  i := 10;
  ShowMessage(VarToStr(i));
end;

var
  i : Integer;
begin
  i := 10;
  ShowMessage(i.ToString());
end;

变体让您可以在其中存储各种类型的值,而类型在编译时可能是未知的。您可以将整数值写入 Variant 类型的单个变量,稍后用字符串值覆盖它。除了值变体记录,其中还存储了 type information。在这些值中,其中一些值自动分配 and/or 引用计数。当从 Variant 变量写入或读取值时,编译器在幕后做了很多事情。

varDispatch 类型的变体得到了编译器的更多特殊对待。 varDispatch表示该值是IDispatch (usually, but not necessarily related to Windows COM technology类型)。 IDispatch 的实例通过 GetTypeInfoCountGetTypeInfo 方法提供有关其方法和属性的信息。您可以使用其 GetIDsOfNames 方法按名称查询信息。

让我们先回答您评论中的问题:

Why does Delphi allow me to use the ToString function even if there is no helper implementing such function for the Variant type?

这就是 Delphi 实现名为 late binding 的概念的方式。它允许您调用编译时类型未知的对象的方法。这个工作的先决条件是底层变体类型支持后期绑定。 Delphi 内置支持 varDispatchvarUnknown 变体的后期绑定,如单元 System.Variants 中的过程 DispInvokeCore 所示。

I don't understand why the ToString function raises exception for Variant type variables.

如上所述,在 运行 时间,您的程序尝试对变体值调用 ToString 方法,在您的情况下,变体值的类型为 varByte。由于它不支持后期绑定(以及更多的序数变体类型),您会遇到异常。

要将变量值转换为字符串,请使用 VarToStr

这是一个使用 Microsoft Speech 进行后期绑定的简单示例 API:

uses
  Winapi.ActiveX,
  System.Win.ComObj;

var
  Voice: Variant;
begin
  CoInitialize(nil);
  try
    Voice := CreateOleObject('SAPI.SpVoice');
    Voice.Speak('Hello, World!');
  finally
    CoUninitialize;
  end;
end.