2013-05-02 8 views
6

Dzisiaj próbuję skompilować mój projekt XE3 w XE4. Pierwszy problem, który napotykam, to metoda Indy'ego FTCPClient.Socket.ReadBytes().Delphi XE4 Indywidualność zgodności między TBytes i TidBytes

Zanim zaakceptował typ TBytes, teraz nalega na TidBytes.

Definicje: TIdBytes = tablica bajtów; TBytes, nie jestem pewien, domyślam się, że to generics coś jak TArray, który jest tablicą bajtów.

Pytanie numer 1: Dlaczego kompilator skarży się, mówiąc, że "[Błąd dcc32] HistoricalStockData.pas (298): E2033 Typy rzeczywistych i formalnych parametrów var muszą być identyczne". Jak widzę, są już identyczne.

Pytanie numer 2: Czy powinienem zmodyfikować mój kod źródłowy za pomocą każdej nowej wersji delphi?

Dzięki.

Odpowiedz

8

Powodem TIdBytes był prosty alias TBytes we wcześniejszych wydaniach Indy 10 był przede wszystkim pod kątem zgodności z SysUtils.TEncoding, który wykorzystuje TBytes. Typ Indy'ego TIdTextEncoding był zwykłym aliasem dla SysUtils.TEncoding w D2009 +, więc TIdBytes musiał być prostym aliasem dla TBytes, aby pasował.

Jednak, TBytes spowodował spory kłopot dla Indy w XE3, głównie z powodu problemów z RTTI z Generics (TBytes jest prostym aliasem dla TArray<Byte> w ostatnich wydaniach Delphi). Tak więc, Indy 10.6 ponownie zaprojektował TIdTextEncoding, aby już nie polegać na SysUtils.TEncoding (były też inne powody), co pozwoliło TIdBytes zmienić się na własny typ tablicy, aby uniknąć problemów XE3 do przodu.

Z drugiej strony, przeszedłeś TBytes, gdzie oczekiwano TIdBytes, więc jest to złe programowanie z Twojej strony, ponieważ w pierwszej kolejności nie podążałeś za zdefiniowanym interfejsem Indy. Wszystkie operacje oparte na bajtach Indy 10, w tym ReadBytes(), zawsze działały tylko na TIdBytes. Fakt, że TIdBytes po cichu zmapowany do TBytes był szczegółem implementacji, na który nie powinieneś polegać w swoim kodzie. Indy 10 oczekuje TIdBytes, więc użyj TIdBytes, wtedy nie będziesz miał błędów kompilatora dotyczących niekompatybilnych typów.

+4

Biblioteki, które wymyślają własne typy zamiast używać równoważnych typów RTL, prowadzą do gettoizacji. W jaki sposób możemy napisać kod, który używa Indy i jego tablicy bajtów i współdziała z inną biblioteką przy użyciu jej tablicy bajtów? –

+0

Najpierw powiedz Embarcadero, aby przestał łamać własne produkty, gdy wprowadzają zmiany RTL. TBytes był zwykłą tablicą dynamiczną (jak teraz TIdBytes). Udało się to z RTTI, Inspektorem obiektów, kompilatorem itp. Następnie zmienili TBT na TArray i zepsuł to wszystko (zły Generics RTTI, zły codegen C++, itp.). Pamiętaj też, że Indy obsługuje wiele języków, a TArray działa inaczej w C++ niż w Delphi. Było wiele powodów, dla których TIdBytes powróciłby do prostej tablicy dynamicznej. Nie zmieniłem tego lekko, a nawet Embarcadero polecił mi to zrobić w tym czasie. –

+3

OK, jestem pewien, że miałeś dobry powód, żeby się zmienić. W moim odczuciu niesłuszne jest to, że w 2013 r. Nadal trwa debata na temat obsługi tablic bajtowych. "Prawidłowe" rozwiązanie, zakładając, że wszystko może być włączone do działania, byłoby dla wszystkich kodów, aby używać 'TArray ' bezpośrednio i dlatego ciesz się specjalnymi regułami kompatybilności typów dla typów ogólnych. Więc w idealnym świecie nie byłoby "TBytes", nie "TIdBytes", a biblioteki mogłyby z powodzeniem współistnieć i współpracować płynnie. –

3

Następujące dwie deklaracje to , a nie to samo, nawet jeśli wydają się takie. Nie są to assignment compatible, mimo że oba oparte są na 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; 

Więc TBytes i TIdBytes nie są tego samego typu, nawet jeśli oboje są zdefiniowane jako array of Byte.

W odniesieniu do pytania 2: Jest to częsty problem z niektórymi kodami stron trzecich. Indy jest szczególnie znany z wprowadzania zmian, które łamią wsteczną kompatybilność, ponieważ decydują się na reorganizację lub przepisanie rzeczy między wersjami. Indy 10 była istotną zmianą w stosunku do Indy 9, IIRC i prawie wymagała przepisania większości kodu, który używał go, jeśli zaktualizowałeś do późniejszej wersji Indy (nawet bez aktualizacji Delphi w tym samym czasie). Jeśli nie chcesz zajmować się tymi zmianami, możesz rozważyć użycie bardziej stabilnego pakietu komunikacji IP. Istnieje kilka dostępnych darmowych pakietów open source.

+0

Uzgodnione, a także wykonane. :-) –

+1

Kto powiedział, że mi się to nie podobało? ;-) –

2

w Indy 10.5.9 się TIdBytes typu określono inaczej, w zależności od obecności istniejącego typu TBytes - patrz jednostki IdGlobal:

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

w Indy 10,6 (w XE4), zgłoszenie zmienia się bezwarunkowo

TIdBytes = array of Byte; 

co oznacza, że ​​wychodząc z Indy 10.6 IdGlobal.TIdBytes różni się od SysUtils.TBytes.

Na drugie pytanie trudno odpowiedzieć, jest to raczej kwestia priorytetów - inne biblioteki nie są odporne na zmiany, na przykład w celu poprawy wydajności lub bezpieczeństwa typu. Również zmiany w języku Delphi mogą zawsze wpływać na istniejący kod.

Powiązane problemy