【问题标题】:Using ToString for Variant variables对 Variant 变量使用 ToString
【发布时间】:2020-05-22 07:58:40
【问题描述】:

以下代码产生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;

【问题讨论】:

  • 您可能会注意到i.ToString,当i 是一个变体时,它的效果与i.SendToVoldemort 一样糟糕。这只是一种不存在的方法。您正在考虑TIntegerHelper.ToString(比如说),但您的i 不是整数,它是一个变体。 (事实上​​,在编译时甚至不知道变体是否包含整数!)
  • @AndreasRejbrand:嗯,所以下一个问题是:为什么 Delphi 允许我使用 ToString 函数,即使没有帮助程序为 Variant 类型实现这样的函数?
  • 因为变体很特殊。它是关于后期绑定、调度接口和类似的东西。我不知道细节,所以我会让更有知识的人回答。
  • 一个变体可以包含一个IDispatch,它使用后期绑定。

标签: delphi tostring delphi-xe7 variant


【解决方案1】:

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

varDispatch 类型的变体可以从编译器获得更多特殊待遇。 varDispatch 表示该值的类型为 IDispatch(通常但不一定与 Windows COM technology 相关)。 IDispatch 的实例通过GetTypeInfoCountGetTypeInfo 方法提供有关其方法和属性的信息。您可以使用它的GetIDsOfNames方法按名称查询信息。

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

为什么 Delphi 允许我使用 ToString 函数,即使没有帮助程序为 Variant 类型实现此类功能?

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

我不明白为什么ToString 函数会引发Variant 类型变量的异常。

如上所述,在运行时,您的程序尝试在变体值上调用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.

【讨论】:

    猜你喜欢
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 2012-10-08
    相关资源
    最近更新 更多