Delphi XE4中TBytes和TidBytes之间的Indy兼容性问题

7
今天我尝试在XE4中编译我的XE3项目。首先遇到的问题是Indy的FTCPClient.Socket.ReadBytes()方法。
以前它接受TBytes类型,现在坚持使用TidBytes。
定义: TIdBytes = Byte 数组; TBytes,我不确定,我猜它是类似于Byte数组的泛型TArray。
问题1: 为什么编译器会抱怨“[dcc32 错误] HistoricalStockData.pas(298): E2033 实际和形式变量参数的类型必须相同”。看起来它们已经是相同的了。
问题2: 我是否应该在每个新版本的Delphi中修改我的源代码?
谢谢。
3个回答

8
在早期的Indy 10版本中,TIdBytes只是TBytes的一个简单别名,主要是为了与使用TBytesSysUtils.TEncoding兼容。在D2009+中,Indy的TIdTextEncoding类型也只是SysUtils.TEncoding的一个简单别名,因此TIdBytes需要成为TBytes的一个简单别名以匹配。

然而,在XE3中,TBytes给Indy带来了很多麻烦,主要是由于泛型的RTTI问题(在最近的Delphi版本中,TBytes只是TArray<Byte>的一个简单别名)。因此,Indy 10.6重新设计了TIdTextEncoding,不再完全依赖于SysUtils.TEncoding(还有其他原因),这样就允许TIdBytes变成自己的数组类型,以避免XE3问题。

另一方面,如果你在需要TIdBytes的地方传递了TBytes,那么这是你的错误编程,没有遵循Indy所定义的接口。所有基于字节的操作,包括ReadBytes(),都只对TIdBytes进行操作。TIdBytes静默地映射到TBytes只是一种实现细节,你不应该在代码中依赖它。Indy 10期望使用TIdBytes,因此请使用TIdBytes,这样就不会出现不兼容类型的编译器错误。

5
自行创造类型而非使用等效的运行库类型只会导致隔离。我们如何编写代码,使用Indy及其字节数组与另一个库进行交互? - David Heffernan
首先告诉Embarcadero在进行RTL更改时停止破坏他们自己的产品。TBytes曾经是一个简单的动态数组(就像现在的TIdBytes一样)。它与RTTI、对象检查器、编译器等完美配合。然后他们将TBytes切换到TArray<Byte>并打破了所有这些(不良泛型RTTI,不良C++代码生成等)。还要记住Indy支持多种语言,并且TArray<T>在C++中的工作方式与Delphi中的不同。因此,有多个原因使TIdBytes回到简单的动态数组。我不轻易做出这种改变,甚至Embarcadero当时也建议我这样做。 - Remy Lebeau
3
好的,我相信你改变的原因是有充分的理由的。对我来说,在2013年还在讨论如何处理字节数组感觉很不对。假设一切都能正常进行,"正确"的解决方案将是所有代码直接使用TArray<T>并享受泛型类型的特殊类型兼容规则。因此,在理想的世界中,不会有TBytesTIdBytes,库可以愉快地共存并平稳交互。 - David Heffernan

3
以下两个声明并不相同,尽管它们看起来是相同的。它们不是赋值兼容的,即使它们都基于字符串数组
type
  TStringArrayOne = array of string;
  TStringArrayTwo = array of string;

var
  AVar1, AVar2: TStringArrayOne;
  AVar3, AVar4: TStringArrayTwo;
begin
  AVar1 := TStringArrayOne.Create('a', 'b', 'c');   // Compiles
  AVar2 := TStringArrayTwo.Create('a', 'b', 'c');   // Won't compile

  AVar3 := TStringArrayTwo.Create('a', 'b', 'c');   // Compiles
  AVar4 := TStringArrayOne.Create('a', 'b', 'c');   // Won't compile
end;

因此,即使它们都被定义为Byte数组TBytesTIdBytes不是相同的类型。

关于您的第二个问题:这是一些第三方代码常见的问题。特别是Indy会进行更改,破坏向后兼容性,因为他们决定在版本之间重新组织或重写东西。我记得Indy 10与Indy 9有很大的变化,并且如果您更新到较新版本的Indy(即使没有同时更新Delphi),则几乎需要重写使用它的大多数代码。如果您不想处理这些更改,您可能需要考虑使用更稳定的IP通信包。还有几个可用的免费开源软件包。


1
谁说我不喜欢呢?;-) - Ken White

2
在Indy 10.5.9中,TIdBytes类型的定义取决于是否存在现有的TBytes类型 - 参见IdGlobal单元。
  {$IFDEF HAS_TBytes}
  TIdBytes = TBytes;
  {$ELSE}
  TIdBytes = array of Byte;
  {$ENDIF}

在Indy 10.6(包含在XE4中),声明已经无条件地更改。
  TIdBytes = array of Byte;

这意味着从Indy 10.6开始,IdGlobal.TIdBytes与SysUtils.TBytes不同。

第二个问题很难回答,��更是一个关于您优先级的问题 - 其他库也不免受到更改的影响,例如为了提高性能或类型安全性。此外,Delphi语言中的更改也可能会影响现有代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接