Pascal 两个异构记录的赋值!


前几天看到一个帖子,讨论两个记录复制,贴主提出了一个解决方案,但是不想用,希望大家集思广益,让人没想到的是方法还真的挺多,这里罗列一下。

这是需要复制的的两种记录

TypeA = record
  value1 : word;
  value2 : word;
  value3 : word;
  end;

TypeB = record
  b1 : byte;
  b2 : byte;    
  end;

方案1:贴主抛的砖1

CopyMemory(@TypeA, @TypeB, Length(TypeB))

方案2:贴主抛的砖2

TypeB.b1 := TypeA.value1 && $FF;

方案3.0:用变体记录

..
TypeAB = packed record
  case boolean of
    false:(a:TypeA);
    true:(b:TypeB);
end;
..

方案3.1:用变体记录是低级形式,需要调整记录的定义形式,否则会由于系统不同上面的结构会产生不同的情况(确实存在BUG)。

type
  TTwoBytes : packed record
    ByteA, ByteB : Byte;
  end;

  TValueRecord : packed record:
    case Boolean of
      True: (Value: SmallInt);
      False: (ValueBytes : TTwoBytes);
    end;
  end;

  TMyRecord = packed record
    Value1, Value2, Value3 : TValueRecord;
  end;

....

var
  MyRecord: TMyRecord;
  MyBytes: TTwoBytes;
begin
  MyRecord := ...; // Fill it with data here
  // Access the words / smallints by something like: MyRecord.Value1.Value
  MyBytes := MyRecord.ValueBytes; // The key bit: type safe assignment
  // Do something with MyBytes.ByteA or MyBytes.ByteB
end;

方案4:利用pascal自带的 Move

procedure CopyAtoB( const A: TypeA; var B: TypeB);
begin
// Assume A is bigger than B.
Move( A, B, SizeOf( TypeB))
end;

//or (with Math unit)

procedure CopyAtoB( const A: TypeA; var B: TypeB);
begin
// No assumptions about A, B sizes.
FillChar( B, SizeOf( B), 0);
Move( A, B, Min( SizeOf( TypeA), SizeOf( TypeB)))
end;

方案5:利用操作符重载

type
    TTypeA = record
      value1 : integer;
      value2 : integer;
      value3 : integer;
    end;

    TTypeB = record
      b1 : byte;
      b2 : byte;
      class operator Implicit(value : TTypeA):TTypeB;
    end;

class operator TTypeB.Implicit(value: TTypeA): TTypeB;
begin
    result.b1 := Hi(value.value1);
    result.b2 := Lo(value.value1);
end;


var a : TTypeA;
    b : TTypeB;
begin
    b := a;
end.

方案6:利用字节流复制

var a : TTypeA;
    bs : TBytesStream;
    bArr : TArray;//array of byte;
begin
    bs := TBytesStream.Create();
    bs.Write(a, sizeof(a));
    bArr := bs.Bytes;
end;

方案6:CopyMemory() (Windows unit)

type
  PTypeA = ^TTypeA;
  TTypeA = record
    value1 : word;
    value2 : word;
    value3 : word;
  end;
  PTypeB = ^TTypeB;
  TTypeB = record
    b1 : byte;
    b2 : byte;
  end;
var
  A: TTypeA = (value1 : 11; value2 : 22; value3 : 33);
  B: TTypeB;
  B1: TTypeB;
  C: {packed?} array of Byte;
begin
  Assert(SizeOf(TTypeA) >= SizeOf(TTypeB));
  //...
  B:= PTypeB(@A)^;
  //...
  SetLength(C, SizeOf(A));
  // TTypeA record to Byte Array
  PTypeA(@C[0])^:= A;
  // Byte Array to TTypeB
  B1:= PTypeB(@C[0])^
end;