【问题标题】:Delphi XE4 Indy compatibility issue between TBytes and TidBytesTBytes 和 TidBytes 之间的 Delphi XE4 Indy 兼容性问题
【发布时间】:2013-04-26 17:17:33
【问题描述】:

今天我尝试在 XE4 中编译我的 XE3 项目。我面临的第一个问题是 Indy 的 FTCPClient.Socket.ReadBytes() 方法。

之前接受TBytes类型,现在坚持TidBytes。

定义: TIdBytes = 字节数组; TBytes,我不确定我猜它是泛型之类的 TArray,它是字节数组。

问题 1: 为什么编译器会抱怨说'[dcc32 Error] HistoricalStockData.pas(298): E2033 Types of actual and form var parameters must be same'。如我所见,它们已经相同了。

问题 2: 我应该用每个新的 delphi 版本修改我的源代码吗?

谢谢。

【问题讨论】:

    标签: delphi indy


    【解决方案1】:

    TIdBytes 是早期 Indy 10 版本中TBytes 的简单别名的原因主要是为了与使用TBytesSysUtils.TEncoding 兼容。 Indy 的 TIdTextEncoding 类型曾经是 D2009+ 中 SysUtils.TEncoding 的简单别名,因此 TIdBytes 需要是 TBytes 的简单别名才能匹配。

    然而,TBytes 在 XE3 中给 Indy 带来了很多麻烦,主要是因为泛型的 RTTI 问题(TBytes 是最近 Delphi 版本中TArray<Byte> 的简单别名)。因此,Indy 10.6 重新设计了 TIdTextEncoding 以不再依赖 SysUtils.TEncoding(这样做还有其他原因),然后允许 TIdBytes 更改为自己的数组类型以避免XE3 问题向前发展。

    另一方面,您传递了 TBytes ,而 TIdBytes 是预期的,因此您的编程很糟糕,因为您一开始就没有遵循 Indy 定义的接口。 Indy 10 的所有基于字节的操作,包括ReadBytes(),始终只对TIdBytes 进行操作。 TIdBytes 静默映射到 TBytes 的事实是您不应该在代码中依赖的实现细节。 Indy 10 需要TIdBytes,所以使用TIdBytes,这样就不会出现关于不兼容类型的编译器错误。

    【讨论】:

    • 图书馆发明自己的类型而不是使用等效的 RTL 类型只会导致贫民窟化。我们如何编写使用 Indy 及其字节数组并使用其字节数组与另一个库交互的代码?
    • 首先告诉 Embarcadero 在他们进行 RTL 更改时停止破坏他们自己的产品。 TBytes 曾经是一个简单的动态数组(就像现在的 TIdBytes 一样)。它与 RTTI、Object Inspector、编译器等一起工作得很好。然后他们将 TBytes 切换到 TArray 并打破了所有这些(糟糕的泛型 RTTI、糟糕的 C++ 代码生成等)。还要记住 Indy 支持多种语言,并且 TArray 在 C++ 中的工作方式与在 Delphi 中不同。因此,让 TIdBytes 回到简单的动态数组有多种原因。我没有轻易做出改变,当时甚至 Embarcadero 都建议我这样做。
    • 好的,我相信你有充分的理由改变。我觉得在 2013 年仍然存在关于如何处理字节数组的争论。假设一切都可以工作,“正确”的解决方案是让所有代码直接使用TArray<T>,从而享受泛型类型的特殊类型兼容性规则。所以在一个理想的世界里,没有TBytes,没有TIdBytes,图书馆可以愉快地共存并顺利互动。
    【解决方案2】:

    以下两个声明不同相同,尽管它们看起来是相同的。它们不是assignment compatible,尽管它们都基于array of string

    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;
    

    所以TBytesTIdBytes 不是同一类型,即使它们都被定义为array of Byte

    关于您的问题 2:这是一些第三方代码的常见问题。 Indy 尤其以做​​出破坏向后兼容性的更改而闻名,因为他们决定在版本之间重新组织或重写事物。 Indy 10 是 Indy 9、IIRC 的重大变化,如果您更新到 Indy 的更高版本(即使没有同时更新 Delphi),几乎需要重写大多数使用它的代码。如果您不想处理这些更改,您可能需要考虑使用更稳定的 IP 通信包。有几个可用的也是免费的开源软件包。

    【讨论】:

    • 谁说我不喜欢它? ;-)
    【解决方案3】:

    在 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 语言的更改总是会影响现有代码。

    【讨论】:

      猜你喜欢
      • 2013-10-24
      • 2013-09-21
      • 1970-01-01
      • 2020-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多