2013-05-02 16 views
6

Heute versuche ich mein XE3-Projekt in XE4 zu kompilieren. Das erste Problem, mit dem ich konfrontiert bin, ist die Methode FTCPClient.Socket.ReadBytes() von Indy.Delphi XE4 Indy Kompatibilitätsproblem zwischen TBytes und TidBytes

Bevor es TBytes akzeptiert, besteht es jetzt auf TidBytes.

Definitionen: TIdBytes = Array von Byte; TBytes, Ich bin nicht sicher, ich denke, es ist Generika so etwas wie TArray, die Array von Byte ist.

Frage Nummer 1: Warum beschwert sich der Compiler, indem er sagt: '[dcc32 Fehler] HistoricalStockData.pas (298): E2033 Die Typen der tatsächlichen und formalen var Parameter müssen identisch sein'. Wie ich sehe, sind sie bereits identisch.

Frage Nummer 2: Sollte ich meinen Quellcode mit jeder neuen Delphi-Version ändern?

Danke.

Antwort

8

Der Grund TIdBytes war ein einfacher Alias ​​für TBytes in früheren Indy 10-Versionen war in erster Linie für die Kompatibilität mit SysUtils.TEncoding, den TBytes verwendet. Indys TIdTextEncoding Typ war ein einfacher Alias ​​für SysUtils.TEncoding in D2009 +, also TIdBytes benötigt, um ein einfacher Alias ​​für TBytes zu sein.Jedoch

, verursacht TBytes ziemlich viel Mühe für Indy in XE3, vor allem wegen der RTTI Probleme mit Generics (TBytes ist ein einfaches Alias ​​für TArray<Byte> in den letzten Delphi Versionen). Also, Indy 10.6 re-designed TIdTextEncoding nicht mehr auf SysUtils.TEncoding überhaupt verlassen (es gab auch andere Gründe dafür), die dann TIdBytes in einen eigenen Array-Typ ändern, um die XE3 Probleme zu vermeiden, vorwärts zu bewegen.

Auf der anderen Seite, haben Sie eine TBytes übergeben, wo eine TIdBytes erwartet wurde, so dass die Programmierung schlecht ist, weil Sie Indys definierte Schnittstelle in erster Linie nicht folgen. Alle bytebasierten Operationen von Indy 10, einschließlich ReadBytes(), wurden immer nur unter TIdBytes ausgeführt. Die Tatsache, dass TIdBytes im Stillen auf TBytes gemappt wurde, war ein Implementierungsdetail, auf das Sie sich in Ihrem Code nicht verlassen sollten. Indy 10 erwartet TIdBytes, also verwenden Sie TIdBytes, dann hätten Sie keine Compilerfehler über inkompatible Typen.

+4

Bibliotheken, die ihre eigenen Typen anstelle von gleichwertigen RTL-Typen erfinden, führen nur zur Ghettoisierung. Wie können wir Code schreiben, der Indy und sein Byte-Array verwendet und über sein Byte-Array mit einer anderen Bibliothek interagiert? –

+0

Teilen Sie Embarcadero zuerst mit, dass sie ihre eigenen Produkte nicht mehr veröffentlichen dürfen, wenn sie RTL-Änderungen vornehmen. TBytes war früher ein einfaches dynamisches Array (wie TIdBytes jetzt). Es funktionierte gut mit RTTI, Objektinspektor, Compiler usw. Dann schalteten sie TBytes zu TArray und brach alles (schlechte Generics RTTI, schlechtes C++ Codegen, usw.). Denken Sie auch daran, dass Indy mehrere Sprachen unterstützt, und TArray funktioniert in C++ anders als in Delphi. Es gab also mehrere Gründe dafür, TIdBytes zu einem einfachen dynamischen Array zurückkehren zu lassen. Ich habe den Wechsel nicht leicht gemacht, und sogar Embarcadero hat empfohlen, dass ich es zu der Zeit mache. –

+3

OK, ich bin sicher, du hattest einen guten Grund, dich zu ändern. Es fühlt sich alles falsch an, dass es 2013 immer noch Diskussionen darüber gibt, wie man mit Byte-Arrays umgehen soll. Die "richtige" Lösung, vorausgesetzt, dass alles zum Laufen gebracht werden könnte, wäre für alle Codes, 'TArray ' direkt zu verwenden und so die speziellen Typkompatibilitätsregeln für generische Typen zu genießen. In einer idealen Welt gäbe es also keine "TBytes", keine "TIdBytes", und Bibliotheken könnten glücklich nebeneinander existieren und reibungslos interagieren. –

3

Die folgenden zwei Deklarationen sind nicht das gleiche, obwohl sie zu sein scheinen. Sie sind nicht assignment compatible, obwohl sie beide auf array of string basieren.

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; 

So TBytes und TIdBytes sind nicht die gleiche Art, auch wenn sie als array of Byte beide definiert sind.

In Bezug auf Ihre Frage 2: Es ist ein häufiges Problem mit einigen Drittanbieter-Code. Indy ist insbesondere dafür bekannt, Änderungen vorzunehmen, die die Abwärtskompatibilität zerstören, weil sie sich dazu entscheiden, Dinge zwischen den Versionen neu zu organisieren oder neu zu schreiben. Indy 10 war eine große Änderung von Indy 9, IIRC, und ziemlich viel erforderte eine Neuschreibung des meisten Codes, der es verwendete, wenn Sie auf die spätere Version von Indy aktualisierten (sogar ohne Delphi gleichzeitig zu aktualisieren). Wenn Sie sich nicht mit diesen Änderungen befassen möchten, sollten Sie sich ein stabileres IP-Kommunikationspaket ansehen. Es gibt mehrere verfügbare, die auch frei sind, Open-Source-Pakete.

+0

Einverstanden, und auch getan. :-) –

+1

Wer hat gesagt, dass es mir nicht gefallen hat? ;-) –

2

In Indy 10.5.9 die Art TIdBytes anders definiert wurde in Abhängigkeit von der Anwesenheit eines TBytes Typ bestehenden - Einheit IdGlobal siehe:

{$IFDEF HAS_TBytes} 
    TIdBytes = TBytes; 
    {$ELSE} 
    TIdBytes = array of Byte; 
    {$ENDIF} 

In Indy 10.6 (in XE4 enthalten), änderte sich die Erklärung bedingungslos

TIdBytes = array of Byte; 

was bedeutet, dass ausgehend von Indy 10.6, IdGlobal.TIdBytes von SysUtils.TBytes unterscheidet.

Die zweite Frage ist schwer zu beantworten, es geht eher um Ihre Prioritäten - auch andere Bibliotheken sind nicht immun gegen Veränderungen, zum Beispiel um die Performance oder die Typensicherheit zu verbessern. Auch Änderungen in der Delphi-Sprache können sich immer auf den vorhandenen Code auswirken.

Verwandte Themen