2013-05-02 15 views
6

Oggi provo a compilare il mio progetto XE3 in XE4. Il primo problema che devo affrontare è con il metodo FTCPClient.Socket.ReadBytes() di Indy.Problema di compatibilità Delphi XE4 Indy tra TBytes e TidBytes

Prima che accettasse il tipo TBytes, ora è in attesa su TidBytes.

Definizioni: TIdBytes = matrice di byte; TBytes, non sono sicuro immagino che sia qualcosa di generico come TArray che è una matrice di Byte.

Domanda numero 1: Perché il compilatore si lamenta dicendo che '[errore dcc32] HistoricalStockData.pas (298): E2033 I tipi di parametri var effettivi e formali devono essere identici'. Come vedo, sono già identici.

Domanda numero 2: Devo modificare il mio codice sorgente con ogni nuova versione delphi?

Grazie.

risposta

8

La ragione TIdBytes era un semplice alias per TBytes in precedenti Indy 10 versioni era soprattutto per la compatibilità con SysUtils.TEncoding, che utilizza TBytes. Il tipo TIdTextEncoding10 di Indy era un semplice alias per SysUtils.TEncoding in D2009 +, quindi TIdBytes doveva essere un semplice alias per TBytes corrispondente.

Tuttavia, TBytes ha causato un po 'di problemi per Indy in XE3, principalmente a causa di problemi RTTI con Generics (TBytes è un semplice alias per TArray<Byte> nelle recenti versioni di Delphi). Quindi, Indy 10.6 ridisegna il TIdTextEncoding per non fare più affidamento su SysUtils.TEncoding (c'erano anche altri motivi per farlo), il che ha permesso di cambiare TIdBytes nel proprio tipo di array per evitare che i problemi XE3 avessero inizio.

D'altra parte, si stava passando un TBytes in cui era previsto un TIdBytes, quindi è una programmazione errata da parte dell'utente per non aver seguito l'interfaccia definita di Indy in primo luogo. Tutte le operazioni basate su byte di Indy 10, incluso lo ReadBytes(), funzionano sempre solo su TIdBytes. Il fatto che TIdBytes mappato in modo invisibile a TBytes era un dettaglio di implementazione a cui non si doveva fare affidamento nel codice. Indy 10 si aspetta TIdBytes, quindi utilizzare TIdBytes, quindi non si avranno errori del compilatore relativi ai tipi incompatibili.

+4

Le librerie che inventano i propri tipi invece di usare tipi di RTL equivalenti portano semplicemente alla ghettizzazione. Come possiamo scrivere codice che usa Indy e il suo array di byte e interagisce con un'altra libreria usando il suo array di byte? –

+0

Prima di dire a Embarcadero di smettere di rompere i propri prodotti quando fanno le modifiche RTL. I TBytes erano una semplice matrice dinamica (come ora TIdBytes). Ha funzionato alla perfezione con RTTI, Object Inspector, compilatore, ecc. Quindi hanno cambiato i TByte in TArray e hanno rotto tutto (difettoso RTTI generico, codegen C++ errato, ecc.). Ricorda inoltre che Indy supporta più lingue e TArray funziona in modo diverso in C++ rispetto a Delphi. Quindi c'erano molti motivi per far tornare TIdBytes su un semplice array dinamico. Non ho fatto la modifica leggermente, e anche Embarcadero mi ha raccomandato di farlo al momento. –

+3

OK, sono sicuro che avevi buone ragioni per cambiare. Mi sembra completamente sbagliato che nel 2013 ci sia ancora un dibattito su come gestire gli array di byte. La soluzione "giusta", supponendo che tutto possa essere fatto funzionare, sarebbe che tutti i codici usassero direttamente 'TArray ' e si godessero le speciali regole di compatibilità del tipo per i tipi generici. Quindi in un mondo ideale non ci sarebbero 'TBytes', no' TIdBytes', e le librerie potrebbero felicemente coesistere e interagire senza intoppi. –

3

Le seguenti due dichiarazioni sono non uguali, anche se sembrano essere. Non sono assignment compatible, anche se entrambi sono basati su 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; 

Così TBytes e TIdBytes non sono dello stesso tipo, anche se sono entrambe definite come array of Byte.

Riguardo alla domanda 2: è un problema comune con alcuni codici di terze parti. Indy in particolare è noto per aver apportato modifiche che interrompono la compatibilità a ritroso perché decidono di riorganizzare o riscrivere le cose tra una versione e l'altra. Indy 10 è stato un grosso cambiamento rispetto a Indy 9, IIRC, e praticamente ha richiesto una riscrittura della maggior parte del codice che lo utilizzava se si aggiornava alla versione successiva di Indy (anche senza aggiornare Delphi allo stesso tempo). Se non vuoi gestire queste modifiche, potresti voler utilizzare un pacchetto di comunicazioni IP più stabile. Sono disponibili diversi pacchetti gratuiti e open source.

+0

D'accordo, e fatto pure. :-) –

+1

Chi ha detto che non mi è piaciuto? ;-) –

2

In Indy 10.5.9 le TIdBytes tipo è stata definita in modo diverso a seconda della presenza di un tipo Tbyte esistente - vedi Scatola IdGlobal:

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

In Indy 10.6 (escluso dalla XE4), la dichiarazione cambiato incondizionatamente

TIdBytes = array of Byte; 

che significa che a partire da Indy 10.6, IdGlobal.TIdBytes è diverso da SysUtils.TBytes.

La seconda domanda è difficile da rispondere, è più una questione di priorità: anche le altre librerie non sono immuni dalle modifiche, ad esempio per migliorare le prestazioni o la sicurezza del tipo. Anche le modifiche nella lingua Delphi possono sempre influire sul codice esistente.

Problemi correlati