加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

为什么将NIL数组赋给Variant会导致在Delphi 6中返回非空数组?

发布时间:2020-12-15 09:28:22 所属栏目:大数据 来源:网络整理
导读:考虑下面的代码,在Delphi 6中编译和运行时没有错误.当我恢复动态字符串数组时,我看到的是一个长度为1的数组,其中一个元素包含一个空字符串.为什么这样,我如何安全地将NIL动态数组分配给Variant并正确恢复?这是代码: TDynamicStringArray = array of string
考虑下面的代码,在Delphi 6中编译和运行时没有错误.当我恢复动态字符串数组时,我看到的是一个长度为1的数组,其中一个元素包含一个空字符串.为什么这样,我如何安全地将NIL动态数组分配给Variant并正确恢复?这是代码:

TDynamicStringArray = array of string;

var
    V: Variant;
    sa: TDynamicStringArray;
begin
    sa := nil;

    V := sa;

    sa := V;

    OutputDebugString('sa has a single element now with an empty string in it when I expect it to be empty.');
end;

解决方法

这里有两个错误.

首先在Variants.DynArrayVariantBounds中.当动态数组为零时,这会错误地返回(0,0)的低/高边界对.它应该返回(0,-1).最新版本的Delphi中修复了此错误.这导致V:= sa返回带有单个空元素的变量数组.

第二个错误影响另一个方向,sa:= V.这个错误仍然存??在于最新版本的Delphi中.这个bug出现在Variants.DynArrayFromVariant中.有一个repeat / until循环遍历输入变量数组并填充输出动态数组.当输入变量数组为空时,它不应该输入repeat / until循环.但是,代码错误地这样做并尝试使用VarArrayGet读取变量数组的元素.由于数组为空,因此会引发运行时错误.我报告了这个:QC#109445.

这是修复错误的一小段代码.请注意,我只考虑数组是一维的情况.如果您需要支持更高维度的数组,那么您可以扩展此方法.

program Project1;

{$APPTYPE CONSOLE}

uses
  Variants;

var
  OriginalVarFromDynArray: procedure(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
  OriginalVarToDynArray: procedure(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);

function DynArrayVarType(typeInfo: PDynArrayTypeInfo): Integer;
const
  tkDynArray  = 17;
begin
  Result := varNull;
  if (typeInfo<>nil) and (typeInfo.Kind=tkDynArray) then
  begin
    Inc(PChar(typeInfo),Length(typeInfo.name));
    Result := typeInfo.varType;
    if Result=$48 then
      Result := varString;
  end;
  if (Result<=varNull) or (Result=$000E) or (Result=$000F) or ((Result>varInt64) and not (Result=varString)) then
    VarCastError;
end;

procedure VarFromDynArray(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer);
var
  VarType,DynDim: Integer;
begin
  DynDim := DynarrayDim(PDynArrayTypeInfo(TypeInfo));
  if DynDim=1 then
  begin
    //only attempt to deal with 1 dimensional arrays
    if DynArray=nil then begin
      VarClear(V);
      VarType := DynArrayVarType(PDynArrayTypeInfo(TypeInfo));
      if VarType = varString then
        VarType := varOleStr;
      V := VarArrayCreate([0,-1],VarType);
      exit;
    end;
  end;
  OriginalVarFromDynArray(V,DynArray,TypeInfo);
end;

procedure VarToDynArray(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer);
var
  DimCount: Integer;
  Len: Integer;
begin
  DimCount:= VarArrayDimCount(V);
  if DimCount=1 then
  begin
    //only attempt to deal with 1 dimensional arrays
    Len := VarArrayHighBound(V,1) - VarArrayLowBound(V,1) + 1;
    if Len=0 then begin
      DynArraySetLength(DynArray,PDynArrayTypeInfo(TypeInfo),1,@Len);
      exit;
    end;
  end;
  OriginalVarToDynArray(DynArray,V,TypeInfo);
end;

procedure FixVariants;
var
  VarMgr: TVariantManager;
begin
  GetVariantManager(VarMgr);
  OriginalVarFromDynArray := VarMgr.VarFromDynArray;
  VarMgr.VarFromDynArray := VarFromDynArray;
  OriginalVarToDynArray := VarMgr.VarToDynArray;
  VarMgr.VarToDynArray := VarToDynArray;
  SetVariantManager(VarMgr);
end;

type
  TDynamicStringArray = array of string;

var
  V: Variant;
  sa: TDynamicStringArray;
begin
  FixVariants;

  sa := nil;
  V := sa;
  sa := V;

  Writeln(Length(sa));
  Readln;
end.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读