测试强制转换 OleVariant 是否会引发异常(不引发异常)

发布于 2024-10-20 10:33:41 字数 460 浏览 5 评论 0原文

在 Delphi 中,我想确定是否可以将特定的 OleVariant 转换为特定的数据类型如果不能则不引发异常。异常不是针对程序流程的,对吧?

我想要的是这样的,其中 Type 可以是 OleVariant 支持的任何内容:

if TryVarAsType(variant, value) then ...

想要的是

try
  value := Type(variant);
  // case where the variant could be converted to a Type
except
  // case where the variant could not be converted to a Type
end;

变体无法转换为布尔值的情况只是正常情况,定期发生,并不表示有任何类型的错误。

In Delphi I want to determine whether a particular OleVariant can be cast to a particular data type without raising an exception if it can't. Exceptions are not for program flow, right?

What I want is something like this, where Type could be anything supported by an OleVariant:

if TryVarAsType(variant, value) then ...

What I don't want is

try
  value := Type(variant);
  // case where the variant could be converted to a Type
except
  // case where the variant could not be converted to a Type
end;

The case where the variant could not be converted to a Boolean is just a normal case that occurs regularly and doesn't indicate any kind of error.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

翻身的咸鱼 2024-10-27 10:33:41

您可以使用 VariantChangeTypeEx 函数构造此类函数。

uses
  VarUtils,
  Variants;

function TryVarAsType( AVariant : OleVariant; const AVarType: TVarType ) :Boolean;
var
   SourceType: TVarType;
begin
  SourceType:=TVarData(AVariant).VType;
  //the types are ole compatible
  if (AVarType and varTypeMask < varInt64) and (SourceType and varTypeMask < varInt64) then
    Result:=
    (SourceType=AVarType) or
    (VariantChangeTypeEx(TVarData(AVariant), TVarData(AVariant), VAR_LOCALE_USER_DEFAULT, 0, AVarType)=VAR_OK)
  else
  Result:=False; //Here you must process the variant pascal types like varString
end;

并像这样使用,

TryVarAsType('1',varInteger);
TryVarAsType('s',varInteger)

这仅适用于

  varEmpty    = $0000; { vt_empty        0 }
  varNull     = $0001; { vt_null         1 }
  varSmallint = $0002; { vt_i2           2 }
  varInteger  = $0003; { vt_i4           3 }
  varSingle   = $0004; { vt_r4           4 }
  varDouble   = $0005; { vt_r8           5 }
  varCurrency = $0006; { vt_cy           6 }
  varDate     = $0007; { vt_date         7 }
  varOleStr   = $0008; { vt_bstr         8 }
  varDispatch = $0009; { vt_dispatch     9 }
  varError    = $000A; { vt_error       10 }
  varBoolean  = $000B; { vt_bool        11 }
  varVariant  = $000C; { vt_variant     12 }
  varUnknown  = $000D; { vt_unknown     13 }
  varShortInt = $0010; { vt_i1          16 }
  varByte     = $0011; { vt_ui1         17 }
  varWord     = $0012; { vt_ui2         18 }
  varLongWord = $0013; { vt_ui4         19 }
  varInt64    = $0014; { vt_i8          20 }

其他类型(pascal 变体)的 ole 兼容变体类型,例如 varStringvarAny 您必须检查源和目标 TVarType 并编写您自己的测试用例。

更新

正如@David 指出的,区域设置可以为相同的值产生不同的结果,因此您必须将此答案视为构建您自己的函数的初始步骤或提示,并且您必须了解区域设置建议的功能中引起的设置问题。

you can construct such function using the VariantChangeTypeEx function.

uses
  VarUtils,
  Variants;

function TryVarAsType( AVariant : OleVariant; const AVarType: TVarType ) :Boolean;
var
   SourceType: TVarType;
begin
  SourceType:=TVarData(AVariant).VType;
  //the types are ole compatible
  if (AVarType and varTypeMask < varInt64) and (SourceType and varTypeMask < varInt64) then
    Result:=
    (SourceType=AVarType) or
    (VariantChangeTypeEx(TVarData(AVariant), TVarData(AVariant), VAR_LOCALE_USER_DEFAULT, 0, AVarType)=VAR_OK)
  else
  Result:=False; //Here you must process the variant pascal types like varString
end;

and use like this

TryVarAsType('1',varInteger);
TryVarAsType('s',varInteger)

this will work with only with ole compatible Variant types

  varEmpty    = $0000; { vt_empty        0 }
  varNull     = $0001; { vt_null         1 }
  varSmallint = $0002; { vt_i2           2 }
  varInteger  = $0003; { vt_i4           3 }
  varSingle   = $0004; { vt_r4           4 }
  varDouble   = $0005; { vt_r8           5 }
  varCurrency = $0006; { vt_cy           6 }
  varDate     = $0007; { vt_date         7 }
  varOleStr   = $0008; { vt_bstr         8 }
  varDispatch = $0009; { vt_dispatch     9 }
  varError    = $000A; { vt_error       10 }
  varBoolean  = $000B; { vt_bool        11 }
  varVariant  = $000C; { vt_variant     12 }
  varUnknown  = $000D; { vt_unknown     13 }
  varShortInt = $0010; { vt_i1          16 }
  varByte     = $0011; { vt_ui1         17 }
  varWord     = $0012; { vt_ui2         18 }
  varLongWord = $0013; { vt_ui4         19 }
  varInt64    = $0014; { vt_i8          20 }

for the another types (pascal variants) like varString, varAny you must check the source and destination TVarType and write your own test cases.

UPDATE

As @David point me out, the locale settings can produce different results for the same values, so you must consider this answer just as initial step or tip to construct your own function and you must aware of locale settings issues caused in the proposed function.

堇色安年 2024-10-27 10:33:41

我不知道内置支持允许动态转换检查失败并出现错误代码而不是异常。

您可以自己手动编码,但这样做会在变体单元中产生大量无法容忍的重复代码。在这种情况下,我认为使用异常比复制依赖于实现的代码的替代方案要好。


作为 RRUZ 最巧妙答案的反例,我提供以下代码:

procedure Main;
var
  v: Variant;
  i: Integer;
  CanConvert: Boolean;
begin
  v := '$1';

  Writeln(BoolToStr(TryVarAsType(v, varInteger), True));

  try
    i := Integer(v);
    if i>0 then begin
      CanConvert := True;
    end;
  except
    CanConvert := False;
  end;
  Writeln(BoolToStr(CanConvert, True));
end;

输出:

False
True

I'm not aware of built-in support that would allow dynamic conversion checking that failed with an error code rather than an exception.

You could hand-code it yourself but doing so would produce an intolerable amount of duplication of the code in the Variants unit. In this case I think that using exceptions is less bad than the alternative of duplicating implementation dependent code.


As a counter-example to RRUZ's most ingeneous answer, I offer the following code:

procedure Main;
var
  v: Variant;
  i: Integer;
  CanConvert: Boolean;
begin
  v := '$1';

  Writeln(BoolToStr(TryVarAsType(v, varInteger), True));

  try
    i := Integer(v);
    if i>0 then begin
      CanConvert := True;
    end;
  except
    CanConvert := False;
  end;
  Writeln(BoolToStr(CanConvert, True));
end;

Output:

False
True
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文