我正在将代码从10.1移植到10.2,这给了我错误:
procedure TForm4.FormCreate(Sender: TObject);
const
CFourBytes: array[0..3] of Byte = (1, 2, 3, 4);
var
LStream: TMemoryStream;
LBuffer: array of Byte;
begin
SetLength(LBuffer, 4);
LStream := TMemoryStream.Create;
LStream.Write(@CFourBytes[0], 4); // E2036 Variable required
LStream.Position := 0;
LStream.ReadData(@LBuffer[0], 4);
end;
我不得不将违规线路更改为LStream.Write(CFourBytes[0], 4);
发生了什么变化?我一直都做错了吗?
问题中的代码确实是在旧版本中编译的,但不应该这样做。10.2中的行为是正确的。
旧版本中发生的事情非常奇怪。编译器在TStream
:中选择此重载
function Write(const Buffer: TBytes; Count: Longint): Longint; overload;
这尤其令人震惊,因为传递给该方法的是静态数组CFourBytes
的地址。它绝对不是TBytes
对象。
现在恰好TBytes
变量是数组第一个元素的地址。TMemoryStream.Write
的TBytes
覆盖中没有任何内容引用该伪TBytes
对象的Length()
。因此,您的代码恰好按预期工作。这显然是一个已经修复的编译器错误。
你的代码总是被破坏,到目前为止,你只是幸运地逃脱了惩罚。你应该修复你的代码。像这样:
LStream := TMemoryStream.Create;
try
LStream.WriteBuffer(CFourBytes, SizeOf(CFourBytes));
SetLength(LBuffer, LStream.Size);
LStream.Position := 0;
LStream.ReadBuffer(LBuffer[0], LStream.Size);
finally
LStream.Free;
end;
请注意,我使用的是WriteBuffer
和ReadBuffer
,而不是Write
和Read
。这些是与TStream
一起使用的首选方法。原因是它们执行错误检查,并在出现错误时引发异常,这与Write
和Read
不同。
也许什么都没有改变。
TStream.Write/Read
方法总是使用未类型化的const/var
参数const Buffer
(help(,并且使用变量的地址是错误的(因为方法(确切地说是编译器(找到变量本身的地址(。
您可能不小心将这些方法与使用类型参数的读/写数据方法混淆,并且其中一个重载版本获得Pointer
类型参数。
这里,ReadData
实现取消引用该指针并在内部使用Read
(Read
依次调用Move
,最后一个例程再次获得缓冲区地址:(