2012-09-10 11 views
6

Conversione da D2007 a XE2, ho convertito questa funzioneCome impostare il valore predefinito per un parametro funzione di tipo TEncoding?

function Add_Line(FileStream : TFileStream; ALine : string) : boolean; 

a

function Add_Line(FileStream : TFileStream; ALine : string; Enc: TEncoding = nil) : boolean; 
var 
    AStr: ANSISTring; 
begin 
    Result := True; 
    if Enc = nil then Enc := TEncoding.ANSI; 
    try 
//Old FileStream.WriteBuffer(Pointer(ALine)^, Length(ALine)); 
    if Enc = TEncoding.UTF8 then 
     AStr := UTF8Encode(ALine) 
    else 
     AStr := ANSIString(ALine); 
    FileStream.WriteBuffer(AStr[1], Length(ALine)); 
    end; 
    except 
    Result := False; 
    end; 
end; 

Motivazione:

  • Cambia codice utilizzando Add_Line il meno possibile

  • Accetta la modifica automatica a Unic ode, solo all'ultimo momento scrivere file di testo a 8 bit (questo è usato in XML e CSV). In futuro potremmo ancora passare ai file UTF-16 se vogliamo.

avrei voluto per definire qualcosa come:

function Add_Line(FileStream : TFileStream; ALine : string; Enc: TEncoding = TEncoding.ANSI) : boolean; 

ma il compilatore si lamenta ;-)

è qualcosa di simile possibile?

+2

La restrizione dei parametri di default per essere valori costanti è uno dei motivi per cui preferisco sempre l'utilizzo di sovraccarichi. –

+0

I sovraccarichi non mi sono mai passati per la mente ;-) –

risposta

12

argomenti di default deve essere una fase di compilazione costante, ma se avete bisogno di qualcosa di più avanzato, è possibile creare sovraccarichi:

function Add_Line(FileStream : TFileStream; ALine : string) : boolean; overload; 
function Add_Line(FileStream : TFileStream; ALine : string; Enc: TEncoding) : boolean; overload; 


function Add_Line(FileStream : TFileStream; ALine : string) : boolean; 
begin 
    Result := Add_Line(FileStream, ALine, TEncoding.ANSI); 
end; 

È anche possibile aggiungere la parola chiave inline per ottenere esattamente lo stesso codice generato che il l'argomento di default avrebbe comportato, se fosse valido.

Nota: non sembra supportare nulla di diverso da TEncoding.ANSI e TEncoding.UTF8. In tal caso, un parametro TEncoding sembra eccessivo, è possibile utilizzare invece un parametro UTF8: Boolean (o rielaborare il codice affinché funzioni con una codifica arbitraria CodePage).

Nota 2: FileStream.WriteBuffer(AStr[1], Length(ALine)); è sbagliato perché Length(ALine) e Length(AStr) Non è necessario essere lo stesso, è necessario utilizzare Length(AStr) invece. Inoltre, AStr[1] può causare un'eccezione quando AStr è una stringa vuota, è possibile aggiungere un caso speciale per chiamare solo WriteBuffer quando AStr non è vuoto.

+0

Per uso futuro, lascerò un parametro TEncoding, e grazie per aver segnalato l'errore di Lunghezza()! Potrebbe portare a dati orribili ;-) –

5

Altri hanno commentato come è possibile specificare un valore predefinito per il parametro TEncoding. Voglio sottolineare che il tuo uso di TEncoding è completamente sbagliato in generale.

TEncoding.UTF8 non è l'unico modo è possibile ottenere un oggetto di codifica UTF-8 (TEncoding.GetEncoding(65001) è un altro modo), in modo da controllare per TEncoding.UTF8 specificamente è la cosa sbagliata da fare. Peggio ancora, stai ignorando completamente qualsiasi codifica non UTF8 e semplicemente codificando qualcos'altro su un semplice AnsiString, che sconfigge l'intero scopo dell'uso di TEncoding. Un utente potrebbe passare in un oggetto di codifica ISO-8859-X, per esempio, e l'output NON sarebbe codificato ISO come richiesto dall'utente.Si può anche cambiare la vostra parametro in un parametro UseUTF8: Boolean = False, invece, perché è così che si sta effettivamente utilizza:

function Add_Line(FileStream : TFileStream; ALine : string; UseUTF8: Boolean = False) : boolean; 
var 
    AStr: AnsiString; 
begin 
    Result := True; 
    try 
    if UseUTF8 then 
     AStr := UTF8Encode(ALine) 
    else 
     AStr := AnsiString(ALine); 
    if AStr <> '' then 
     FileStream.WriteBuffer(AStr[1], Length(AStr)); 
    except 
    Result := False; 
    end; 
end; 

Il modo corretto di utilizzare TEncoding è quella di lasciar fare la codifica reale, non fare il codifica te:

function Add_Line(FileStream : TFileStream; ALine : string; Enc: TEncoding = nil) : boolean; 
var 
    AStr: TBytes; 
begin 
    if ALine = '' then 
    begin 
    Result := True; 
    Exit; 
    end; 
    Result := False; 
    try 
    if Enc = nil then Enc := TEncoding.Ansi; 
    AStr := Enc.GetBytes(ALine); 
    // GetBytes() returns 0 bytes if it fails to encode, it does not raise an exception! 
    if Length(AStr) = 0 then Exit; 
    FileStream.WriteBuffer(AStr[0], Length(AStr)) 
    except 
    Exit; 
    end; 
    Result := True; 
end; 
Problemi correlati