Проверьте, вызовет ли приведение OleVariant исключение (без возбуждения исключения) - PullRequest
2 голосов
/ 03 марта 2011

В Delphi я хочу определить, может ли конкретный OleVariant быть приведен к определенному типу данных без вызова исключения, если он не может .Исключения не для выполнения программы, верно?

Что я хочу, это что-то вроде этого, где Type может быть чем угодно, поддерживаемым OleVariant:

if TryVarAsType(variant, value) then ...

Что я не могу 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;

Случай, когда вариант не может быть преобразован в логическое значение, является обычным случаем, который происходит регулярно и не указывает на какую-либо ошибку.

Ответы [ 2 ]

3 голосов
/ 03 марта 2011

Вы можете создать такую ​​функцию, используя функцию 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)

, это будет работать только с oleсовместимые типы вариантов

  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 }

для других типов (варианты паскаля), таких как varString, varAny, вы должны проверить источник и пункт назначения TVarType и написать свои собственные контрольные примеры.

ОБНОВЛЕНИЕ

Как заметил @David, настройки локали могут давать разные результаты для одних и тех же значений, поэтому вы должны рассматривать этот ответ просто как начальный шаг или совет для создания своей собственной функции.и вы должны знать о проблемах с настройками языкового стандарта, вызванных предложенной функцией.

2 голосов
/ 03 марта 2011

Мне не известна встроенная поддержка, которая позволяла бы выполнять динамическую проверку преобразования, которая завершилась ошибкой с кодом ошибки, а не с исключением.

Вы можете вручную написать его, но это приведет к недопустимому количеству дублирования кода в блоке Variants. В этом случае я думаю, что использование исключений менее вредно, чем альтернатива дублирования кода, зависящего от реализации.


В качестве контрпримера для самого изобретательного ответа 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
...