2012-09-10 21 views
6

La conversión de D2007 a XE2, que convierten esta función¿Cómo establecer el valor predeterminado para un parámetro de función de 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; 

Justificación:

  • Cambiar código usando Add_Line lo menos posible

  • Aceptar el cambio automático a Unic ode, solo en el último momento escriba archivos de texto de 8 bits (esto se usa en XML y CSV). En el futuro, podríamos movernos a los archivos UTF-16 si lo deseamos.

me hubiera gustado para definir algo como:

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

pero el compilador se queja ;-)

¿Es posible algo así?

+2

La restricción de los parámetros predeterminados para ser valores constantes es una de las razones por las que siempre estoy a favor de usar sobrecargas. –

+0

Las sobrecargas nunca pasaron por mi mente ;-) –

Respuesta

12

argumentos por defecto debe ser una constante en tiempo de compilación, pero si necesitas algo más avanzado, puede crear sobrecargas:

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; 

Incluso puede agregar la palabra clave inline para obtener exactamente el mismo código generado que la el argumento predeterminado habría resultado, si fuera válido.

Nota: no parece admitir nada más que TEncoding.ANSI y TEncoding.UTF8. En ese caso, un parámetro TEncoding parece excesivo, en su lugar podría usar un parámetro UTF8: Boolean (o volver a trabajar el código para trabajar con una codificación arbitraria CodePage).

Nota 2: FileStream.WriteBuffer(AStr[1], Length(ALine)); es incorrecto porque Length(ALine) y Length(AStr) no tiene que ser el mismo, se debe utilizar Length(AStr) lugar. Además, AStr[1] puede dar como resultado una excepción cuando AStr es una cadena vacía, puede agregar un caso especial para llamar solo al WriteBuffer cuando AStr no esté vacío.

+0

Para un uso futuro, lo dejo como un parámetro de TEncoding, y gracias por señalar el error de longitud(). Podría llevar a datos horribles ;-) –

5

Otros han comentado sobre cómo puede especificar un valor predeterminado para el parámetro TEncoding. Quiero señalar que su uso de TEncoding es completamente incorrecto en general.

TEncoding.UTF8 no es la única forma en que puede obtener un objeto de codificación UTF-8 (TEncoding.GetEncoding(65001) es otra forma), por lo que comprobar TEncoding.UTF8 específicamente es lo que no debe hacer. Peor aún, está ignorando por completo las codificaciones que no son UTF8 y simplemente codificando todo lo demás en un simple AnsiString, que anula todo el propósito de usar TEncoding. Un usuario podría pasar un objeto de codificación ISO-8859-X, por ejemplo, y su salida NO tendría codificación ISO como la solicitada por el usuario.Usted puede también cambiar el parámetro en un parámetro UseUTF8: Boolean = False lugar, porque esa es la forma en que está efectivamente utilizando:

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; 

La forma correcta de utilizar TEncoding es dejar que haga la codificación real, no lo haga el codificándose usted mismo:

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; 
Cuestiones relacionadas