2012-10-11 38 views
5

Xem xét mã bên dưới biên dịch và chạy mà không có lỗi trong Delphi 6. Khi tôi khôi phục mảng chuỗi động, thay vì nhìn thấy một mảng trống trong sa, tôi thấy một mảng có độ dài là 1 với một phần tử duy nhất chứa chuỗi rỗng. Tại sao điều này và làm thế nào tôi có thể an toàn gán một mảng động NIL cho một biến thể và phục hồi nó đúng cách? Đây là mã:Tại sao gán một mảng NIL cho một Biến thể gây ra một mảng không trống để được trả về trong Delphi 6?

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; 
+0

có lẽ typecast là 'biến thể -> chuỗi -> mảng của chuỗi' thay vì' biến thể -> con trỏ -> mảng của chuỗi' –

Trả lời

5

Có hai lỗi ở đây.

Trước hết là Variants.DynArrayVariantBounds. Khi mảng động là nil, lỗi này trả về một cặp giới hạn thấp/cao là (0, 0). Nó sẽ trả về (0, -1). Lỗi này được sửa trong các phiên bản mới nhất của Delphi. Điều đó làm cho V := sa trả về một mảng biến thể với một phần tử đơn lẻ.

Lỗi thứ hai ảnh hưởng đến hướng khác, sa := V. Lỗi này vẫn còn hiện diện trong các phiên bản mới nhất của Delphi. Lỗi này là trong Variants.DynArrayFromVariant. Có một vòng lặp repeat/until đi qua mảng biến thể đầu vào và điền vào mảng động đầu ra. Khi mảng biến thể đầu vào rỗng, nó không được nhập vào vòng lặp repeat/until đó. Tuy nhiên, mã này thực hiện sai và cố đọc một phần tử của mảng biến thể với VarArrayGet. Kể từ khi mảng là trống rỗng, mà gây ra một lỗi thời gian chạy. Tôi đã báo cáo điều này: QC#109445.

Đây là một mã rất đơn giản để sửa lỗi. Lưu ý rằng tôi chỉ xem xét trường hợp các mảng là một chiều. Nếu bạn cần hỗ trợ mảng chiều cao hơn thì bạn có thể mở rộng phương pháp này để làm như vậy.

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. 
+0

Cảm ơn bạn. Đó là một lỗi thực sự lớn. –

Các vấn đề liên quan